How To Shape Orientation of Ipad-like Popover? - swift

I have 2 questions.
1) Currently, my iPad popover is working but the arrow is pointing downward on top of button. How do I flip it so the arrow points upward and the ViewController is under the button?
2) how do I keep the layout the same if I turn my phone (it will become full screen).
Below is my code for the popover that has emojis.
#IBAction func emojiButtonTapped(_ sender: UIButton) {
let VC = storyboard?.instantiateViewController(withIdentifier: "EmojiController") as! EmojiViewController
VC.preferredContentSize = CGSize(width: 200, height: 100)
let navController = UINavigationController(rootViewController: VC)
navController.modalPresentationStyle = UIModalPresentationStyle.popover
let popOver = navController.popoverPresentationController
popOver?.sourceView = sender
popOver?.sourceRect = sender.bounds
popOver?.delegate = self
self.present(navController, animated: true, completion: nil)
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}

To answer the first question: You can use the permittedArrowDirections property of the UIPopoverPresentationController to give a hint which arrows you allow. In your case, use UIPopoverArrowDirection.up
The second question I do not quite understand - what do you mean with
how do I keep the layout the same if I turn my phone
What layout?

Related

Swift - Popover controller shows up on wrong corner depending on load time

I recently started having an issue where the popover controller will some times show up on the wrong corner. When it works correctly, the popover source is a button on the upper right corner. This is what happens most o the time. Now, when I land on this page "too quickly" from a specific route, the popover shows up on the upper left corner.
Another thing that is weird is that when loading is artificially delayed (like when I set break points for debugging) the popover shows up correctly.
Since it seemed to be a timing issue, I tried moving the navigation configuration from viewDidLoad to viewDidAppear, but this didn't work.
This function is called from viewDidLoad:
func configureNav() {
if canAddDoc == true {
let customButton = UIButton(type: .system)
customButton.setImage(with: .add, tintColor: UIColor.white, imageEdgeInsets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
customButton.addTarget(self, action: #selector(showAddDocSheet), for: .touchUpInside)
addButton = UIBarButtonItem(customView: customButton)
}
shareButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.action,
target: self,
action: #selector(shareButtonPressed))
navigationItem.rightBarButtonItems = (addButton == nil) ? [shareButton!] : [shareButton!, addButton!]
#objc func showAddDocSheet() {
guard let addButton = addButton else { return }
self.displayActionSheet(sourceButton: addButton)
}
}
func displayActionSheet(sourceButton: UIBarButtonItem) {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
//Action sheet code goes here
if let popoverController = actionSheet.popoverPresentationController {
popoverController.barButtonItem = sourceButton
popoverController.sourceView = sourceButton.customView
popoverController.permittedArrowDirections = .up
}
self.present(actionSheet, animated: true, completion: nil)
}
This may sound a weird solution but something similar happened to me before and it got solved when setting the animation to false while presenting the VC ,
self.present(actionSheet, animated: false, completion: nil)

My UIViewcontroller is not filling the entire screen?

I have a very simple app with two UIviewcontrollers. I want to dismiss one and present another one. However, when I do this (code below), the second viewcontroller does not fill the screen, instead it hovers over the top one and can easily get dismissed if you swipe from the top down (you can just about see the first viewcontroller at the top)?
VC-1:
#objc private func picksAction(){
print("picks button pressed")
let layout = UICollectionViewFlowLayout()
let viewController = GridPicksCollectionViewController(collectionViewLayout: layout)
let navController = UINavigationController()
navController.pushViewController(viewController, animated: true)
self.present(navController, animated: true) {}
}
Result:
Set modalPresentationStyle to .fullScreen:
navController.modalPresentationStyle = .fullScreen

Swift | UIViewController not showing as PopUp but Fullscreen

So i have a viewcontroller which is basically an alert window which is supposed to be a popup and be dismissed by the tap on outside its frame.
But whenever i call that VC, it is always displayed as fullscreen and not as a pop up window.
I have tried a couple of ways to do this, namely as mentioned below.
if let exp : String = expiredVehicles[i] {
expiredVehicleNumber = expiredVehicles[i]
let popUpVC = SubscriptionExpired()
popUpVC.modalTransitionStyle = .crossDissolve
popUpVC.modalPresentationStyle = .popover // also tried other presentation styles but none work and it is still fullscreen
popUpVC.view.backgroundColor = UIColor.white.withAlphaComponent(0.8)
self.present(popUpVC, animated: true, completion: nil)
}
in case anyone need to see the definition of that VC, i will be glad to share it
i feel i should mention that the VC to be displayed as a popup is inheriting UIViewController
Any insight that might help would be great.
Thanks for the input
One potential way is to add a tap gesture recognizer to your View, which dismisses the VC.
But this will only be helpful if this popup has read-only info and doesn't require any further action from the user.
func addTapRecognizer(){
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap))
self.view.addGestureRecognizer(tap)
}
#objc func handleTap(){
// dismiss the VC here
}
}
You can call following method to show popup:
let popupVC = SubscriptionExpired()
popupVC.modalPresentationStyle = .overCurrentContext
self.addChild(popupVC)
popupVC.view.frame = self.view.frame
self.view.addSubview(popupVC.view)
popupVC.didMove(toParent: self)
}
Then, for removing that popup you can use:
UIView.animate(withDuration: 0.25, animations: {
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0
}, completion: { (finished) in
if finished {
self.view.removeFromSuperview()
}
})
In that case I have a button inside popup and whenever that button pressed above method triggers. Can you please try it? I can edit my answer according to your needs.
You need to implement this in you presenting view controller:
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .none
}
UIPopoverPresentationController displaying popover as full screen

Possible to create a UITableView that appears from the corner of a View Controller

I would like to model a table view after one found in the Todoist app (see below), is it possible to do this without and additional framework? If so how would I go about doing this?
You can create a view controller with a UITableView and present it as UIPopoverPresentationController
let vc = UIViewController()
vc.modalPresentationStyle = .popover
vc.preferredContentSize = CGSize(width: 200, height: 200)
let popUp = vc.popoverPresentationController
popUp?.permittedArrowDirections = .up
popUp?.delegate = self
popUp?.sourceView = sender as! UIView // here set the frame of the button that the arrow points to when popup is shown
present(vc, animated: true, completion: nil)
//
Inside the vc that you presents the popup make it implements the delegate UIPopoverPresentationControllerDelegate and write this method
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}

on click on label go to next page

When I created a button earlier it had the ability to be an "action" IBA function..
How can I create the same thing with a label? so when I click the label my app will direct to a new page. (and how can I make it to direct to a new page? would I have to make a totally new view and in some way link it to that)
Please bare in mind, I'm a totally new to swift and have already come along way with my program,but its been pieces from several tutorials and therefor I might have a hard time understanding your answer the first time.
You can use UITapGestureRecognizer for that and below is simple example for you:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRectMake(0, 0, 200, 21))
label.center = CGPointMake(160, 284)
label.textAlignment = NSTextAlignment.Center
label.userInteractionEnabled = true
label.text = "I'am a test label"
self.view.addSubview(label)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTap:")
label.addGestureRecognizer(gestureRecognizer)
}
func handleTap(gestureRecognizer: UIGestureRecognizer) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("next")
self.presentViewController(vc, animated: true, completion: nil)
}
}
Result:
Project sample for more Info.
Swift 3
1- Make sure you've checked the "User Interaction Enabled" in attributes inspector.
2- Code:
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(YourVC.labelTapped))
yourLabel.addGestureRecognizer(gestureRecognizer)
3- Use the func:
func labelTapped() {
print("labelTapped tapped")
}