My popover extends all the whole way down to the bottom of the ViewController - swift

I have spent a full day now building and re-building a simple popover view. But no matter what I do the popover view extends all the way down to the bottom of the ViewController the popover is displayed in. I'm a newbie but have googled this the whole day and can't find any solutions that works for me. I will appreciate any help! Find my code below:
ViewController:
class ViewController: UIViewController,
UIPopoverPresentationControllerDelegate {
...
#IBAction func studyButtonPressed(sender: AnyObject) {
self.performSegueWithIdentifier("StudyPopover", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "StudyPopover" {
let vc = segue.destinationViewController
let controller = vc.popoverPresentationController
if controller != nil {
controller?.delegate = self
}
}
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
Here is a screenshot of the result. The popover is supposed to be 50 by 50, but it extends right down to the bottom of the ViewController.

So I have finally been able to find a solution for this issue. I had a breakthrough when I realised that the popover worked fine when on most device simulations but didn't work for iPhone 6 plus. Then I could narrow down my search for solutions and finally found that I had to add traitCollection: UITraitCollection to my adaptivePresentationStyleForPresentationController function.
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .None
}
This makes the popover behave the same way either it's on a normal sized iPhone, iPhone 6 plus or iPad device.

Related

Value not passing between viewControllers

Struggling to get my viewControllers to send value from the main viewController to a second. I want it to happen on a button click, I'm going to get the value from the button and pass it to the new form. But it just isn't working.
Code for main ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func butClick(_ sender: UIButton) {
NSLog("Button Pressed : %#",[sender .currentTitle])
//var tt = [sender .currentTitle]
// Create the view controller
let vc = TimesTablesViewController(nibName: "TimesTablesViewController", bundle: nil)
vc.passedValue = "xx"
self.performSegue(withIdentifier: "pushSegue", sender: nil)
}
}
Code for second viewController called TimesTablesViewController:
class TimesTablesViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
var passedValue:String = ""
override func viewDidLoad() {
super.viewDidLoad()
titleLabel?.text = "\(passedValue) Times Table"
}
}
I've followed tutorials but can't seem to solve the problem! Thanks for any help!
Replace
self.performSegue(withIdentifier: "pushSegue", sender: nil)
with
self.present(vc,animated:true,completion:nil)
or ( if the current vc is inside a naigation )
self.navigationController?.pushViewController(vc,animated:true)
Using
self.performSegue(withIdentifier: "pushSegue", sender: nil)
is fit with storyboards not xibs and if this your case then you need to use the above line only inside the button action with implementing this method inside the source vc
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "pushSegue" {
if let nextViewController = segue.destination as? TimesTablesViewController{
nextViewController.passedValue = "xx"
}
}
}
I’m assuming that the new view controller is appearing, but you’re simply not seeing the data. If so, you’re evidently using storyboards. The TimesTablesViewController(nibName:bundle:) only works if you’re using XIB/NIBs and manually presenting new view controller.
If you’re really using storyboards, simplify your butClick method:
#IBAction func butClick(_ sender: UIButton) {
NSLog("Button Pressed")
performSegue(withIdentifier: "pushSegue", sender: self)
}
But implement prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? TimesTablesViewController {
destination.passedValue = "xx"
}
}
Assuming the above fixes your problem, I might suggest a further simplification. Notably, if your butClick(_:) method is really only calling performSegue, you can segue to this next scene without any #IBAction method at all:
remove butClick(_:) entirely;
remove the connection between the button and the butClick method in IB, on the “Connections Inspector” tab in the right panel; and
control-drag from the button previously hooked up to butClick(_:) to the scene for TimesTablesViewController.
That will simplify your code further.

popover doesn't display on iphone

I followed this UIPopoverPresentationController on iPhone doesn't produce popover but doesn't produce popover on iphone.
Here is the code of viewcontroller
class ViewController:UIViewController,UIPopoverPresentationControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "second"{
let secondVC = segue.destination
let controller : UIPopoverPresentationController = secondVC.popoverPresentationController!
controller.delegate = self
}
}
/* Popover delegate method */
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
}
I am not able to show new viewcontroller using present as popover in iphone. (ios 10/xcode8)
After clicking on button secondViewController should popover on that button.
After using this delegate method it is producing popover on iphone.
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}

unwind segue not triggering

I have been learning swift and have made the foundation of most of my app. I have the following storyboard
app storyboard
Everything works fine. For example, I have an unwind segue on the add course view controller that triggers when you press save and you are returned to the 'your courses' view controller.
When you are on the my courses view controller, you can select a course and the topics are displayed, you can then select a topic and you are taken to an update score view controller, this all works fine.
However, my problem is this. I want to make it so that when you select save in the updatescore view controller, an unwind segue is triggered (the same as in the add course) and you are returned to the list of topics in the topics view controller.
However, I have followed many tutorials and obviously got it working before. (My action method for the unwind segue is in the correct topics view controller) but when i press save, the unwind segue is not returning me to the topics view controller.
Could anyone suggest a reason for this? I have spent a lot of time trying to find an answer and gone through many tutorials but have not managed to solve it.
I have also included a screen shot of the connections of the triggered segues for my save button to show that it is set up. Showing triggered segue for save button
i have the following code in the update score view controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if saveButton === sender {
print("save button selected")
}
}
But even this is not getting triggered when I click on save.
Many thanks
UPDATE:
After following Ronatorys advice My view controller for the update score is as follows but it is still not working:
import UIKit
class UpdateScoreTableViewController: UITableViewController {
#IBOutlet weak var topicGettingUpdated: UITextField!
#IBOutlet weak var newScore: UITextField!
#IBOutlet weak var saveButton: UIBarButtonItem!
var index:Int?
var Topics:[String]!
var TopicToUpdate:String?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let uiBarButtonItem = sender as? UIBarButtonItem else {
print("There is no UIBarButtonItem sender")
return
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 0 && indexPath.row == 0 {
newScore.becomeFirstResponder()
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
But the prepare for segue is not even getting triggered.
Like Craig in the comments said, it's not that easy to find the problem. So I just build a simple app where you can follow the steps as guide and see if you forgot something to setup the functionality right. Hope it will help you. Note: Code is in Swift 3.0, but should be easy to adopt to 2.*
1. Storyboard with two View Controllers:
2. Declare the action method for the unwind segue in the FirstViewController.swift:
class FirstViewController: UIViewController {
// action method for the unwind segue
#IBAction func updateScore(_ segue: UIStoryboardSegue) {
print("Back in the FirstViewController")
}
}
3. Connect the Save button in the Storyboard with the action method (with ctrl + drag):
4. Connect your Save button with the SecondViewController.swift file, to use it for checking in your prepareSegue method (with ctrl + drag):
5. Add the prepare(for:sender:) method to your SecondViewController.swift:
class SecondViewController: UIViewController {
#IBOutlet weak var saveButtonPressed: UIBarButtonItem!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// check safely with guard that your save button is the sender and you can use it
// if not print message
guard let uiBarButtonItem = sender as? UIBarButtonItem else {
print("There is no UIBarButtonItem sender")
return
}
// check if you selected the save button
if saveButtonPressed == uiBarButtonItem {
print("save button selected")
}
}
}
Result:
The sample app you can find here
I did not manage to get the unwind segue to work but instead used
navigationController!.popViewControllerAnimated(true)
as a work around and this works fine.

Swift performSegueWithIdentifier shows black screen

I have read through a lot of different posts regarding this issue, but none of the solutions seemed to work for me.
I started a new app and I placed the initial ViewController inside a navigation controller. I created a second view and linked them together on the storyboard with a segue. The segue works successfully, and I can see the data I am transferring in a print statement from the second screen, but the screen shows black.
WelcomeScreen:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segueToTraits"{
if let gender = self.selectedGender{
let traitVC = segue.destinationViewController as? TraitViewController
traitVC!.gender = gender
}
}
}
func sendGenderToTraitsView(gender : String?){
performSegueWithIdentifier("segueToTraits", sender: self)
}
#IBAction func button1(sender: UIButton) {
selectedGender = boyGender
self.sendGenderToTraitsView(selectedGender)
}
#IBAction func button2(sender: UIButton) {
selectedGender = girlGender
self.sendGenderToTraitsView(selectedGender)
}
Storyboard:
Link to image of my storyboard
My segue is set as follows:
Link to image of my segue information
Also, my viewControllers are named WelcomeViewController and TraitViewController. They have storyboard id's of welcomeVC and traitsVC.
Any help would be incredibly appreciated. Let me know if you need any other information.
By following the steps that #ronatory had laid out so well for me in the accepted answer, I was able to see that I had set up my TraitViewController as a UIPageViewController instead of UIViewController.. and so it didn't generate any errors, but it just took me to a black screen. Feel silly that I read through my code so many times and never noticed this.
Main point: If you're getting a black screen on a ViewController randomly, make sure your class is extending the correct parent class.
in my case:
class TraitViewController: UIPageViewController {
needed to be
class TraitViewController: UIViewController {
I've build your app and everything works, maybe you've missed something, here is my solution (Note: Code is in Swift 3.0, but should be easy to adopt it to Swift 2.*):
The storyboard:
Set the segueToTraits identifier:
Set the TraitViewController class as custom class in the storyboard:
The view controller with the buttons:
import UIKit
class ViewController: UIViewController {
let boyGender = "boy"
let girlGender = "girl"
var selectedGender: String?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueToTraits"{
if let gender = self.selectedGender {
let traitVC = segue.destination as? TraitViewController
traitVC!.gender = gender
}
}
}
func sendGenderToTraitsView(gender : String?){
performSegue(withIdentifier: "segueToTraits", sender: self)
}
#IBAction func button1(sender: UIButton) {
selectedGender = boyGender
self.sendGenderToTraitsView(gender: selectedGender)
}
#IBAction func button2(sender: UIButton) {
selectedGender = girlGender
self.sendGenderToTraitsView(gender: selectedGender)
}
}
The trait view controller:
import UIKit
class TraitViewController: UIViewController {
var gender: String = ""
override func viewDidLoad() {
super.viewDidLoad()
print("gender: \(gender)")
}
}
Result:
You can find the sample project here

SWIFT: No idea how to get back the selected value from a popover to the calling controller

I just going crazy on Swift Popover “return” values. I am new to Objectiv-C as well as SWIFT but I try to focus on SWIFT.
I checked out tutorials around Google and StackOverflow about how to manage iOS popovers, learned a lot but the last peace I couldn’t make it. It is great so see how easy it is made using Swift and Xcode 6, love it, but I could not figure out how to get back the selected value from my popover to my calling view controller.
So here is my problem:
(SIDENOTE: I am using SWIFT and do all using storyboard)
I have created a master ViewController with a button to select currencies. This button opens a “select currency” popover (linked to the CurrencyTableViewController (CTV) by CTRL-Dragging it to the CTV-Controller.
So far so good. The thing is, I have no idea how to get back the selected table row (currency) from the CTV-Table ;-( So I need the selected currency (table row) in the calling ViewController.
This is an excerpt from my ViewController (which is calling the popover)
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
[...]
// This button is calling the popover
#IBAction func buttonCurrency(sender: AnyObject) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let controller = segue.destinationViewController as? CurrencyTableViewController {
controller.popoverPresentationController?.delegate = self
return
}
}
[...]
Hopefully somebody can help me with that missing last mile how to get back the selected row value back to my ViewController.
Thanks in advance
Cheers
John
I made quick example, hope it helps:
// This is you popover's class
#objc protocol CurrencySelectedDelegate {
func currencySelected(currName: String)
}
class MyPopOverController: UIViewController {
weak var delegate: CurrencySelectedDelegate?
#IBAction func readyButtonPressed(sender: AnyObject) {
// Do what you want
delegate?.currencySelected("Euro/Dollar etc....")
// close popover
}
}
// ViewController
class ViewController: UIViewController, CurrencySelectedDelegate {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "mySegue" { // your identifier here
let controller = segue.destinationViewController as! MyPopOverController
controller.delegate = self
}
}
}
And remember just declare that currencySelected function in your ViewController.