I have a toolbar with a UIBarButtomItem at the left corner with the label Admin
I need to show a popover when it taps it, but it appears in a wrong place, it appears at the top left of the screen:
This is the function to open the popover:
// this IBAction is assigned only to the Admin bar button item
#IBAction func openAdmin(sender: UIBarButtonItem) {
let alertController = UIAlertController(title: nil, message: "Elige una opciĆ³n", preferredStyle: .ActionSheet)
// action button initializations... ... ...
let barButtonItemSize = sender.valueForKey("view")
alertController.popoverPresentationController?.sourceView = self.view
alertController.popoverPresentationController?.sourceRect = barButtonItemSize!.frame
presentViewController(alertController, animated: true, completion: nil)
}
Also I get this warning on the console when I touch the Admin bar button:
Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates
What am I doing wrong? or What do I need to do to present the popover at the top of the Admin?
Replace
alertController.popoverPresentationController?.sourceView = self.view
alertController.popoverPresentationController?.sourceRect = barButtonItemSize!.frame
with
alertController.popoverPresentationController?.sourceView = sender
alertController.popoverPresentationController?.barButtonItem = sender
Related
When I open a calendar event in my app using EKEventViewController using the code below it correctly displays my event in a modal view.
let eventModalVC = EKEventViewController()
eventModalVC.event = myEvent
eventModalVC.allowsEditing = true
present(eventModalVC, animated: true, completion: nil)
In portrait mode (using iOS 15) I can dismiss the modal using a swipe-down gesture. However, when I change to landscape orientation, the gesture does not work, and there is no back or cancel button either (like there is for the EKEventEditViewController). I could not find any property of the view controller that would enable me to dismiss it.
So the user is either stuck or has to turn the device into portrait mode. How can I fix this?
I was hoping that the EKEventViewController offers a similar convenient and intuitive way to dismiss it in landscape view as it does in portrait view but have not had any luck.
To get the back button I now enclosed my modal view in its own navigation controller. That reveals a "Done" button (as well as a delete button). Neither button dismisses the view. That can be done by implementing EKEventViewDelegate in the parent view controller.
let eventModalVC = EKEventViewController()
eventModalVC.event = myEvent
eventModalVC.allowsEditing = true
let nc = UINavigationController(rootViewController: eventModalVC)
eventModalVC.delegate = self
present(nc, animated: true, completion: nil)
...
// EKEventViewDelegate
func eventViewController(_ controller: EKEventViewController, didCompleteWith action: EKEventViewAction) {
if action == .done {
controller.dismiss(animated: true)
}
// handle deletion as well if needed
}
I am want to simple a UIAlertView on the bottom of the screen when opening a ViewController.
Right now, I create an alert view, show it after 2 seconds and hide the alert.
However, the alert view only shows in the center of the screen.
How do I reposition it on the bottom of the screen?
Here is my code:
let alert = UIAlertController(title: "", message: "Please Swipe To Refresh After 2 seconds", preferredStyle: .alert)
alert.view.frame.origin.x = 150
alert.view.frame.origin.y = 250
self.present(alert, animated: true, completion: nil)
let indicator = UIActivityIndicatorView(frame: alert.view.bounds)
indicator.autoresizingMask = [.flexibleWidth, .flexibleHeight]
alert.view.addSubview(indicator)
indicator.isUserInteractionEnabled = false
indicator.startAnimating()
let when = DispatchTime.now() + 2
DispatchQueue.main.asyncAfter(deadline: when) {
alert.dismiss(animated: true, completion: nil)
}
You can't move and UIAlertControllerwith its presentation style set and even if there will be a workaround don't use it. In order to achieve what you want you have different options:
Use a simple UIView subclass that simply requires in the show method the view you want to use as a super view
Create a UIViewController subclass and present it using a UIPresentationController, this could be pretty hard if you are new to iOS development
Use one of the already available libraries on github, for instance this
Use (.... , preferredStyle: .actionSheet) in the constructor of UIAlertController
I implemented the accepted answer from here How to display activity indicator in center of UIAlertController?
But it doesn't work, all that is displayed is the title "Creating New User" and no activity indicator is displayed. While running in the debugger I noticed that with the posted code indicator by default has its visibility set to false, so I explicitly added a line to set it to true, but it made no difference.
Here then is the code from the accepted answer, with that additional line added. Why is the activity indicator not displayed?
func displaySignUpPendingAlert() -> UIAlertController
{
//create an alert controller
let pending = UIAlertController(title: "Creating New User", message: nil, preferredStyle: .alert)
let indicator = UIActivityIndicatorView(frame: pending.view.bounds)
indicator.autoresizingMask = [.flexibleWidth, .flexibleHeight]
//add the activity indicator as a subview of the alert controller's view
pending.view.addSubview(indicator)
indicator.isUserInteractionEnabled = false // required otherwise if there buttons in the UIAlertController you will not be able to press them
indicator.isHidden = false
indicator.startAnimating()
self.present(pending, animated: true, completion: nil)
return pending
}
I am trying to create a pop over and when I present the view controller, the background is always solid black and the size is full screen.
I can't seem to figure out what's wrong and here is the code that I have
#IBAction func distancePopOver( sender : UIBarButtonItem){
//a UIViewController that I created in the storyboard
let controller = storyboard!.instantiateViewControllerWithIdentifier("distancePopOver")
controller.modalPresentationStyle= UIModalPresentationSTyle.PopOver
controller.preferredContentSize = CGSizeMake(200,30)
self.presentViewController(controller, animated: true, completion: nil)
//Configure the Popover presentation controller
let popController = (controller.popoverPresentationController)!
popController.permittedArrowDirections = UIPopoverArrowDirection.Down
popController.barButtonItem = sender
popController.delegate = self
}
Whenever I click on the UIBarButtonItem, it presents the view in full screen, but shouldn't it be the size I specify in line 5?
Popovers are quite finicky now. First, you are going to want to configure the popoverPresentationController before you present it.
Secondly, make sure your arrow direction is pointing the way the arrow points and not where the content is respective to the UIBarButtonItem. So, if its inside UIToolbar (and is near the bottom of the screen) you'll want .Down otherwise if its a navigation bar (near the top) you'll want to use .Up.
#IBAction func distancePopOver( sender : UIBarButtonItem){
//Configure the Popover presentation controller
let popController = (controller.popoverPresentationController)!
popController.permittedArrowDirections = .Down // .Up
popController.barButtonItem = sender
popController.delegate = self
//a UIViewController that I created in the storyboard
let controller = storyboard!.instantiateViewControllerWithIdentifier("distancePopOver")
controller.modalPresentationStyle = .Popover
controller.preferredContentSize = CGSizeMake(200,30)
presentViewController(controller, animated: true, completion: nil)
}
Now if you got this far and its still not working, its because the popover's default behavior in a compact size class is to fill the screen. Since you are already setting your view controller to be the popover's delegate you'll just need to implement this delegate function: adaptivePresentationStyleForPresentationController(_:traitCollection:) and return .None for the presentation style. This will allow you to even show a real looking popover on the iPhone. See my blog post: iPhone Popover for a full example of doing this.
I'm using this function I've found in this site but it saves the whole screen with the navigation bar but no the status bar.
func screenShotMethod() {
let layer = UIApplication.sharedApplication().keyWindow!.layer
let scale = UIScreen.mainScreen().scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil)
let alertSaved = UIAlertController(title: "Saved", message: "", preferredStyle: .ActionSheet)
alertSaved.addAction(UIAlertAction(title: "Ok", style: .Default, handler: {action in
self.view.removeGestureRecognizer(self.gesture)
}))
presentViewController(alertSaved, animated: true, completion: nil)
}
What I need is just take a snapshot from the end of the navigation bar to the bottom.
If you change the layer you are attempting to screenshot from the keyWindow's view to your view controller's view, the navigation bar (assuming you have your view controller embedded in a navigation controller rather than adding a nav bar as a subview of your view) and the status bar will be omitted from the screenshot.
let layer = view.layer
If you have blank space at the top where the navigation bar was, you can adjust the frame to cut this out.