Hi I am looking to make a pop out table view similar to the one below and with selectable cells. Any help would be great thanks!
Here is what I would like to style it after
You will want to make use of UIPopoverPresentationController.
Make a tableviewController with the data you want to be able to select
Make a button that will send the action so you can present the popover
Do something with the item selected from the popover.
The second item above looks something like this (my own code example):
#IBAction func shareAction(_ sender: UIButton) {
let controller = ShareVC()
controller.socialPost = self.item
controller.modalPresentationStyle = .popover
// configure the Popover presentation controller
let popController: UIPopoverPresentationController? = controller.popoverPresentationController
popController?.permittedArrowDirections = [.up, .down]
popController?.delegate = self
// in case we don't have a bar button as reference
popController?.sourceView = sender
popController?.sourceRect = sender.frame
popController?.backgroundColor = .white
self.parentViewController?.present(controller, animated: true, completion: { })
}
In my case the 'ShareVC" is a UITableViewController with item sharing options. Pretty similar to your screenshot as far as layout goes.
This will present that popover from the button that was tapped. Then again, you just need to handle the selection of the items from that ViewController.
Related
Hi I've been trying to change my back button in my application's navigation bar. The problem is that I see the change when I load the view twice.
I've searched for the answer several times but I don't see what I really want. In fact, I'm new at this language so it's difficult.
What I tried is putting the following lines in the viewWillAppear method and others*:
nav?.navigationBar.backItem?.title = "Messages"
The result is that when I enter the view I see the back button's title as Back. Then if I press on that button and enter the view again the title changes as I want. On the other hand, what I want is to change the title when I load the view first.
*-> I've tried the same line in viewDidLoad too see if that does anything and in viewWillDisappear of the previous view, but nothing happens.
You are using method a change back button in your current ViewController it is wrong, because your navigationBar configured in past controller. If you use Storyboard, please will try this method in your parent controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let backItem = UIBarButtonItem()
backItem.title = "Messages"
navigationItem.backBarButtonItem = backItem
}
If you init newController in your parentController, you must to modify your a backButton in parentController, example:
// It's action for any button witch present your newController
#objc private func presentDetailViewContorller() {
let weatherDetailController = WeatherDetailController()
let navController = NavigationController(rootViewController: weatherDetailController)
let backItem = UIBarButtonItem()
backItem.title = "Messages"
navController.backBarButtonItem = backItem
self.present(navController, animated: true, completion: nil)
}
Good luck!
I have a UIViewController that implements UITableViewDelegate, UITableViewDataSource and that contains a UITableView as a member variable. When a user click on one of the rows of that table, the app performs a storyboard segue to open the detail view controller. That detail view controller of course has a button in the top left of the screen that is the "back" button to go back up to the UIViewController with the UIViewTable.
So, suppose that I want to programmatically "click" that back button. How exactly would I do that in swift? This is the most recent version of swift (swift 4?) in XCode 10.1.
UPDATE:
So here is how I solved this. As the answers below show, it is possible to use self.navigationController?.popViewController(animated: true) to just return to the previous view controller. What I discovered I also wanted to do, however, was to call a specific method in that view controller so that it executed a certain behavior once it got shown. It turns out that is also possible, but in my case it was a bit tricky, since that prior view controller was actually a UITabBarController. Therefore I had to get the ViewController that I was interested in from the UITabBarController. I did it like this:
let numvc = navigationController!.viewControllers.count
let tvc:UITabBarController = navigationController!.viewControllers[numvc-2] as! UITabBarController
let my_vc: MyCustomVC = tvc.viewControllers![0] as! MyCustomVC
my_vc.some_function()
Here of course MyCustomV is my custom view controller class and some_function() is the method I want to call on that class. Hope this helps someone.
When You run a segue you perform a "pushViewController" method to the next view, so if you want to go back to the previous view programmatically you just have to do is pop the last view like so:
self.navigationController?.popViewController(animated: true)
UPDATE
You just need the if statement if you have multiple segues from that viewController, if not, you can delete and just cast the next view as you wish and set the properties, let the autocomplete write the *prepare(for segue... * method for you, so You don't run into any problems
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourSegueName" {
let destinationVC = segue.destination as! CustomViewController
destinationVC.labelExample.text = "Some text I'm sending"
}
}
Are you sure you need to "click" the button?
If all you need is to dismiss details view controller, you can just call navigationController?.popViewController(animated: true)
Or if you want to deal directly with button, you can tell it to send its actions: backButton.sendActions(for: .touchUpInside)
Or if you absolutely need to show button clicking animation, then you will need something like this (you should play and choose suitable delay):
backButton.isHighlighted = true
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
backButton.isHighlighted = false
backButton.sendActions(for: .touchUpInside)
}
In my app I'm using some pickerviews that appear when I click on a textfield, that works fine!
I wanted to do the same when I click on a Left Bar Button Item. I can't do it with the button because buttons doesn't have inputView property, needed for associate the pickerview to the button (in this case). So I want to have a hidden textfield that is programmatically clicked when I click on the button (when it's clicked it show the pickerview and change the button name, that's all done)
Is that possible?
The best I can do right know is something like this
txtFantasma.perform(
#selector(becomeFirstResponder),
with: nil,
afterDelay: 0.1
)
It works fine, but just work at the first time.
EDIT1:
I've tried to make it with buttons... The popover is showing, now I wanted to click in one button and dismiss the popover and pass data to the main viewcontroller.
class ViewPopup:UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btTituloAsc(_ sender: UIButton) {
let next = self.storyboard?.instantiateViewController(withIdentifier: "mainview") as! ViewController
next.ordenacao = "TituloAsc"
self.present(next, animated: true,completion:nil)
}
}
This works, but the main controller is showed without the Navigation Bar! How can I do the same but show de Navigation Bar?
The simplistic way to do it, is just display the pickerView as a popover once the user taps the button and then change the buttons title accordingly.
I have a view controller with a toolbar with 3 UIButtons that open a new view controller as a popover. I created the segues in Storyboard and selected "Present as Popover". The popovers work but when the user taps on another button while a popover is currently open, I get this error:
Warning: Attempt to present <Fingerpainter.OpacityViewController: 0x79095110> on <Fingerpainter.DrawingViewController: 0x7b278000> which is already presenting <Fingerpainter.BrushSizeViewController: 0x79573770>
Is there a way to like make sure all popovers are closed before opening a new one? Here's my prepareForSegue method in the main ViewController (containing the toolbar):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let identifier = segue.identifier ?? ""
let popoverPresentationController = segue.destinationViewController.popoverPresentationController
popoverPresentationController!.delegate = self
switch identifier {
case Storyboard.BrushSizeSegueIdentifier:
if let brushSizeViewController = popoverPresentationController?.presentedViewController as? BrushSizeViewController {
// set properties in brushSizeViewController
}
case Storyboard.OpacitySegueIdentifier:
if let opacityViewController = popoverPresentationController?.presentedViewController as? OpacityViewController {
//set properties in opacityViewController
}
case Storyboard.ColorSegueIdentity:
if let colorViewController = popoverPresentationController?.presentedViewController as? ColorViewController {
//set properties in colorViewController
}
default:
break
}
}
Is there a way to like make sure all popovers are closed before opening a new one
It's the other way around. It's your job to make sure that while the popover is present, a button that summons another popover is not tappable. You can do this by disabling the button, but more commonly, in order to coordinate the disabling of the button with the presence of the popover, it's done by adjusting the popover presentation controller's passthroughViews.
Unfortunately there's a massive and long-standing bug where even setting the passthroughViews to nil doesn't prevent toolbar buttons from being tappable. The workaround is to do it with a delay. A lot of my popover code adds this sort of thing:
if let pop = popoverPresentationController {
delay(0.1) {
pop.passthroughViews = nil
}
}
(where delay is described here: https://stackoverflow.com/a/24318861/341994).
I would like to seque programmatically to a "setup-VC" when the initial setup is not done. This works, BUT in this case I don't want to show the back button on the "setup-VC".
What I've done till now:
I've created two VC. (main-VC and setup-VC)
The code of main-VC:
...
if InitialSetupIsDone == true {
println("Loading the data...") //PPP
} else {
println("Segue to setup screen...") //PPP
self.performSegueWithIdentifier("segueToSetup", sender: self)
}
...
// Pull any data from the view controller which initiated the unwind segue.
#IBAction func segueToSetup(sender: UIStoryboardSegue)
{
let sourceViewController: AnyObject = sender.sourceViewController
}
In the main-VC I've created an unwind-segue ("EXIT"-action? - red icon at the top of the VC) and named it "segueToSetup".
At last point I've connected the "setup-VC" with the "main-VC" while dragging an segue from main-VC (yellow Icon top left) to the setup VC.
Then it would look like this:
(The upper connection goes directly from setup sign to the "setup-VC")
The goal for me now would be to kind of "hide" the back button in "setup-VC" while the initial setup is not done. Maybe I've don't create the unwind segue right... !? Thx
Write this line in destination VC viewDidLoad
navigationController?.navigationItem.setHidesBackButton(true, animated: true)
In viewWillAppaer method also write this
navigationController?.navigationItem.setHidesBackButton(true, animated: true)
This disabled the button for me:
let backButton = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.Plain, target: navigationController, action: nil)
navigationItem.leftBarButtonItem = backButton