Call a View from another ViewController Swift - swift

I have a ViewController that has a UIView set on top of it and a button that opens a popover to another ViewController. I want a button on the popover view controller to set the UIView to disable. How do I reference the UIView from the first view controller from a button in the second view controller?
EDIT:
Below is code that I use to call the popover view controller. Notice how I call dimView.isHidden = false from this first viewcontroller. I want to run dimView.isHidden = true from the popover view controller.
let popover = storyboard?.instantiateViewController(withIdentifier: "PopoverVC")
popover?.modalPresentationStyle = .popover
popover?.popoverPresentationController?.delegate = self as? UIPopoverPresentationControllerDelegate
popover?.popoverPresentationController?.sourceView = self.view
popover?.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popover?.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
dimView.isHidden = false
self.present(popover!, animated: false)
EDIT 2:
Below is my popover view controller. Since it is not called PopoverVC. I updated the answer to include let popover = storyboard?.instantiateViewController(withIdentifier: "PopoverVC") as! PopOverViewController but still no luck.
import UIKit
var parentController:UIViewController?
class PopOverViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func closeButton(_ sender: Any) {
self.dismiss(animated: false, completion: nil)
}
}
EDIT 3:
class ViewController: FormViewController {
override func viewWillAppear(_ animated: Bool) {
dimView.isHidden = true
}
#IBOutlet weak var dimView: UIView!

You can pass a reference to your current view controller when presenting your PopoverVC and then you can access its view from PopoverVC. Just create a property in PopoverVC that can store the reference, like var parentController:UIViewController?
let popover = storyboard?.instantiateViewController(withIdentifier: "PopoverVC") as! PopoverViewController
popover?.modalPresentationStyle = .popover
popover?.popoverPresentationController?.delegate = self as? UIPopoverPresentationControllerDelegate
popover?.popoverPresentationController?.sourceView = self.view
popover?.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popover?.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
popover?.dimView = self.dimView
dimView.isHidden = false
self.present(popover!, animated: false)
PopOverViewController:
class PopOverViewController: UIViewController {
var dimView:UIView?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func closeButton(_ sender: Any) {
self.dismiss(animated: false, completion: nil)
}
}

Related

Problem with delegates removing annotation

I have two screens. The first one (firstViewController) has a mapView with a UITapGestureRecognizer. When the user taps the screen, an annotations is added to the map and the second screen (secondViewController) is presented.
When the user dismisses the secondViewController and comes back to the first one, the annotation should be removed. I know I have to use delegation, but I just can't make it to work.
This is the code I have now:
class firstViewController: UIViewController, AnnotationDelegate {
let mapView = MKMapView()
var temporaryPinArray = [MKPointAnnotation]()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mapView
let gesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
mapView.addGestureRecognizer(gesture)
secondVC.annotationDelegate = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
mapView.frame = view.bounds
}
#objc func handleTap(_ gestureReconizer: UILongPressGestureRecognizer) {
let location = gestureReconizer.location(in: mapView)
let coordinates = mapView.convert(location, toCoordinateFrom: mapView)
mapView.removeAnnotations(mapView.annotations)
let pin = MKPointAnnotation()
pin.coordinate = coordinates
temporaryPinArray.removeAll()
temporaryPinArray.append(pin)
mapView.addAnnotations(temporaryPinArray)
// Present secondViewController
let secondVC = SecondViewController()
panel.set(contentViewController: secondVC)
panel.addPanel(toParent: self)
}
func didRemoveAnnotation(annotation: MKPointAnnotation) {
mapView.removeAnnotation(annotation)
}
}
Second View Controller
protocol AnnotationDelegate {
func didRemoveAnnotation(annotation: [MKPointAnnotation])
}
class SecondViewController: UIViewController {
var annotationDelegate: AnnotationDelegate!
let mainVC = firstViewController()
let closeButton: UIButton = {
let button = UIButton()
button.backgroundColor = .grey
button.layer.cornerRadius = 15
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(closeButton)
closeButton.addTarget(self, action: #selector(dismissPanel), for: .touchUpInside)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
closeButton.frame = CGRect(x: view.frame.width-50, y: 10, width: 30, height: 30)
}
#objc func dismissPanel() {
self.dismiss(animated: true, completion: nil)
annotationDelegate.didRemoveAnnotation(annotation: mainVC.temporaryPinArray)
}
}
Thank you so much for your help!
You created a new instance of firstViewController inside SecondViewController. This instance is unrelated to the actual first one:
let mainVC = firstViewController()
This means that temporaryPinArray is different as well. So instead of passing in this unrelated array...
#objc func dismissPanel() {
self.dismiss(animated: true, completion: nil)
annotationDelegate.didRemoveAnnotation(annotation: mainVC.temporaryPinArray)
}
Just change the function to take no parameters instead:
protocol AnnotationDelegate {
func didRemoveAnnotation() /// no parameters
}
#objc func dismissPanel() {
self.dismiss(animated: true, completion: nil)
annotationDelegate.didRemoveAnnotation() /// no parameters
}
And inside firstViewController's didRemoveAnnotation, reference the actual temporaryPinArray.
func didRemoveAnnotation() {
mapView.removeAnnotations(temporaryPinArray) /// the current array
}

iOS 13 - Right Bar Button Item goes offset in Modal Sheet presentation

I have this strange problem with iOS 13 and its new sheet cards style modal presentation.
From ViewController1 I modal present ViewController2 embedded in a NavigationController, and everything works fine.
From ViewController2, I then modal present ViewController3 embedded in a NavigationController, and I get the Right Bar Button offset.
Here is a video of the problem: does anybody have a fix?
Main View Controller
import UIKit
let vc1identifier = "vc1identifier"
let vc2identifier = "vc2identifier"
class ViewController: UIViewController {
#IBAction func tap1(_ sender: UIButton) {
if let navigation = self.storyboard?.instantiateViewController(withIdentifier: vc1identifier) as? UINavigationController,
let nextVC = navigation.contentViewController as? UnoViewController {
//self.navigationController?.pushViewController(nextVC, animated: true)
self.present(navigation, animated: true, completion: nil)
}
}
}
extension UIViewController {
var contentViewController: UIViewController {
if let navcon = self as? UINavigationController {
return navcon.visibleViewController!
} else {
return self
}
}
}
Second View Controller
import UIKit
class UnoViewController: UIViewController {
#IBOutlet weak var barButton: UIBarButtonItem!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
barButton.title = "GotoVC2"
}
#IBAction func pressThis(_ sender: UIBarButtonItem) {
if let navigation = self.storyboard?.instantiateViewController(withIdentifier: vc2identifier) as? UINavigationController,
let nextVC = navigation.contentViewController as? DueViewController {
self.present(navigation, animated: true, completion: nil)
}
}
}
I came across the same issue.
Solution is easy, you just need to tell navigationbar it needs layout like this
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 13.0, *) {
navigationController?.navigationBar.setNeedsLayout()
}
}

How to show another View controller when a label is clicked

Juts like clicking a button to show another view contoller, is there a way to do that with a label?
Call below function
NOTE: Please set identifier same which you are you in below code
class firstViewController: UIViewController {
#IBOutlet weak var yourlabel: UILabel
override func viewDidLoad() {
super.viewDidLoad()
self.addGesture()
}
func addGesture() {
let tap = UITapGestureRecognizer(target: self, action: #selector(self. labelTapped(_:)))
tap.numberOfTapsRequired = 1
self.yourlabel.isUserInteractionEnabled = true
self.yourlabel.addGestureRecognizer(tap)
}
#objc
func labelTapped(_ tap: UITapGestureRecognizer) {
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let SecondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.navigationController?.pushViewController(SecondVC, animated: animated)
}
}
Second ViewController
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}

UIPopoverPresentationController popover displays over the entire view

I am trying to create a rightBarButtonItem that appears throughout my app. When this barItem is clicked I want to show a modal popup using UIPopoverPresentationController. I have been able to get the button to show up on the barItem on all the views. However when i click on the button the xib takes over the entire view (including nav bar, see image below). Please see the class below:
class MyAppsNavigationController: UINavigationController, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.navigationBar.barTintColor = Colors.Red01.color()
self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "Ellipsis"), style: .plain, target: self, action: #selector(displayMenu(sender:)))
}
func displayMenu(sender: UIBarButtonItem)
{
let filterVC = DropdownMenuController(nibName: "DropdownMenuController", bundle: nil)
let nav = UINavigationController(rootViewController: filterVC)
nav.modalPresentationStyle = UIModalPresentationStyle.popover
//nav.isNavigationBarHidden = true
nav.preferredContentSize = CGSize(width: 200, height: 300)
let popover = nav.popoverPresentationController! as UIPopoverPresentationController
popover.permittedArrowDirections = .up
popover.delegate = self
popover.barButtonItem = self.navigationItem.rightBarButtonItem
popover.sourceView = self.view;
var frame:CGRect = (sender.value(forKey: "view")! as AnyObject).frame
frame.origin.y = frame.origin.y+20
popover.sourceRect = frame
popover.delegate = self
self.present(nav, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Result when clicked on the button:
When clicked the popup takes over entire view:
Any chance you're not using the right delegate method? I think this looks better:
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
Also, in this case sourceView and sourceRect is not needed: specifying a barButtonItem for the popover presentation controller is sufficient.
https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller/1622314-barbuttonitem

Why is the message not showing up?

I created a pop up, but nothing is showing up, I added UIViewControllers as the pop ups. Why is it not working? http://puu.sh/hreL9/75081b2a90.png
class interestViewController: UIViewController, UIPopoverPresentationControllerDelegate {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "popoverSegue" {
let interestViewController = segue.destinationViewController as! UIViewController
interestViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
interestViewController.popoverPresentationController!.delegate = self
}
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
I believe you don't need a segue in this case. You can use the example I listed below. It shows a Popover from the button when you press it.
import UIKit
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
var myPopover : UIPopoverPresentationController?
#IBAction func buttonPressed(sender: UIButton) {
// you can init your own View Controller here
var popOverView = self.storyboard?.instantiateViewControllerWithIdentifier("interestViewController‌​") as! interestViewController
popOverView.preferredContentSize = CGSize(width: 250, height: 200);
var destNav = UINavigationController(rootViewController: popOverView)
destNav.modalPresentationStyle = UIModalPresentationStyle.Popover
self.myPopover = destNav.popoverPresentationController
self.myPopover?.delegate = self
self.myPopover?.sourceView = self.view
var theFrame = sender.frame
self.myPopover?.sourceRect = theFrame
destNav.modalPresentationStyle = UIModalPresentationStyle.Popover
destNav.navigationBarHidden = true
self.presentViewController(destNav, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
}