I'm creating a share sheet where someone can share the text from a text field. I've got it working on the iPhone, but the app crashes on the iPad. I know that it has to be in a popover form and have had this issue back in the day of Objective-C, but I can't seem to figure it out on Swift. This is my code that I've got going for the share sheet:
#IBAction func myShareButton(sender: AnyObject) {
// Hide the keyboard
textView.resignFirstResponder()
// Check and see if the text field is empty
if (textView.text == "") {
// The text field is empty so display an Alert
displayAlert("Warning", message: "You haven't written anything yet!")
} else {
// We have contents so display the share sheet
displayShareSheet(textView.text!)
}
}
// Show Warning
func displayAlert(title: String, message: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(alertController, animated: true, completion: nil)
return
}
// Display Share Sheet
func displayShareSheet(shareContent:String) {
let activityViewController = UIActivityViewController(activityItems: [shareContent as NSString], applicationActivities: nil)
presentViewController(activityViewController, animated: true, completion: {})
}
I implemented share sheets today as well and had the exact same issue. You need to add this before presenting.
if let popoverPresentationController = activityController.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: CGRectGetMidX(view.bounds), y: CGRectGetMidY(view.bounds), width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0) //Removes arrow as I dont want it
}
Line 1 sets the source view.
Line 2 I use to Center the popover right in the middle (I use it in SpriteKit and the popover is not attached to anything)
Line 3 I use to remove the arrow as I don't want it.
Hope this helps
for Swift 3/4
Depends on #crashoverride777 Answer
if let popoverPresentationController = activityVC.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0) //Removes arrow as I dont want it
}
Related
How to show keyboard when UIAlertController is present with Custom View and UITextField? I mean I want to keyboard automatically show without user touch the UITextField in alert view.
My code like below to make a Alert.
func callAlertConfirmation() {
let vc = UIViewController()
vc.preferredContentSize = CGSize(width: 250, height: 70)
let textBookmark = UITextField(frame: CGRect(x: 10, y: 0, width: 230, height: 40))
textBookmark.placeholder = "Typing folder name"
textBookmark.font = UIFont.systemFont(ofSize: 15)
textBookmark.textColor = UIColor.black
textBookmark.borderStyle = UITextField.BorderStyle.roundedRect
textBookmark.autocorrectionType = UITextAutocorrectionType.no
textBookmark.keyboardType = UIKeyboardType.alphabet
textBookmark.returnKeyType = UIReturnKeyType.done
textBookmark.contentVerticalAlignment = UIControl.ContentVerticalAlignment.center
textBookmark.textAlignment = NSTextAlignment.left
textBookmark.clearButtonMode = .whileEditing
vc.view.addSubview(textBookmark)
let alert = UIAlertController(title: "Create New Folder", message: nil, preferredStyle: .alert)
alert.setValue(vc, forKey: "contentViewController")
let actOKButton = UIAlertAction(title: "OK", style: .default) { (_) -> Void in
// action When User Okay
}
alert.addAction(actOKButton)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
alert.preferredAction = actOKButton
present(alert, animated: true)
}
And when I call
callAlertConfirmation
I get the result like this picture:
But I want to picture like below when I call
callAlertConfirmation
But when I use
alert.addTextField
I get keyboard automatically show when alert present.
Thanks in advance.
What
As #C4747N already said, you need to call
.becomeFirstResponder()
When
You want to call this method as you present the alert:
present(alert, animated: true) {
textBookmark.becomeFirstResponder()
}
The way you want to "read" this is like:
Present the alert and once you're done execute the completion body (make the alert's textField first responder)
I may be wrong but whenever I want a UITextView or UITextField to show a keyboard immediately i do:
textBookmark.becomeFirstResponder()
This question already has answers here:
Is there any way to add UIPickerView into UIAlertController (Alert or ActionSheet) in Swift?
(12 answers)
Closed 5 years ago.
I would like to show an alert that contains an UIPickerView inside. Is it possible ? Any idea to do it ?
Thank you very much!
UPDATE
Finally I used this fantastic library to make cool custom alerts:
https://github.com/vikmeup/SCLAlertView-Swift
Try this:
let alertView = UIAlertController(
title: "Select item from list",
message: "\n\n\n\n\n\n\n\n\n",
preferredStyle: .alert)
let pickerView = UIPickerView(frame:
CGRect(x: 0, y: 50, width: 260, height: 162))
pickerView.dataSource = self
pickerView.delegate = self
// comment this line to use white color
pickerView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.2)
alertView.view.addSubview(pickerView)
let action = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)
alertView.addAction(action)
present(alertView, animated: true, completion: { _ in
pickerView.frame.size.width = alertView.view.frame.size.width
})
How to display image in center of alert viewController with transparent background of alert viewController.
I wrote following code.
let image = UIImage(named: "ic_no_data")
let imageView = UIImageView(frame: CGRectMake(220, 10, 40, 40)
let alertMessage = UIAlertController(title: "image", message: "", preferredStyle: .Alert)
let backView = alertMessage.view.subviews.last?.subviews.last
backView?.layer.cornerRadius = 10.0
backView?.backgroundColor = UIColor.lightGrayColor()
alertMessage.view.addSubview(imageView)
let action = UIAlertAction(title:"", style: .Cancel, handler: nil)
action.setValue(image, forKey: "image")
alertMessage .addAction(action)
self.presentViewController(alertMessage, animated: true, completion: nil)
It looks like this.
Please help me to solve this problem and thanks to all.
UIAlertController doesn't support such changes in view hierarchy you'd be better using a custom extensible component that mimics the behavior of UIAlertController. The problem with UIAlertController is that you don't know how Apple will change its view hierarchy in the next version of iOS. And each time they change something you'll have to add code for a specific version of iOS which is really bad from the maintainability point of view.
For example CustomIOSAlertView: https://github.com/wimagguc/ios-custom-alertview.
you can store you reference of imageView an alertMessage, and in completion of the present viewController you have the exact size of the alert view, so you can adjust the image according to the current alert rect.
try this code is in swift3 :
self.present(alertMessage, animated: true, completion: {
var frame = self.alertMessage.view.frame
frame.origin = CGPoint(x: 0, y: 0) // add your location
self.imageView.frame = frame
})
I have used a popoverPresentationController on iOS Swift and i have put both an image and text in the popover?
The issue i am having is that the content is too big for the popover? is it possible to set the dimensions?
Pictures are below of both the issue i am having and the trial code and error message?
let myAlert = UIAlertController(title: "\n\n\n\n\n\n", message: "Correct answer selected, move on to next level", preferredStyle: UIAlertControllerStyle.actionSheet)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default)
{
// action in self.dismiss(animated: true, completion: nil)
action in self.performSegue(withIdentifier: "goSegue1", sender: self)
self.musicEffect.stop()
}
// put image into action sheet
let imageView = UIImageView(frame: CGRect(x: 70, y: -30, width: 140, height: 140))
imageView.image = #imageLiteral(resourceName: "wellDone2.png")
myAlert.addAction(okAction);
myAlert.view.addSubview(imageView)
// display the alert messgae
myAlert.popoverPresentationController?.sourceView = view
myAlert.popoverPresentationController?.sourceRect = (sender as AnyObject).frame
myAlert.preferredContentSize = CGSize(width: 500, height: 800)
Issue
The size of the popover is not controlled by the PopoverPresentationController. The PopoverPresentationController only specifies how to present content, but the content itself, including size, is set by the view from which you have obtained the controller, in your case myAlert.
You have the right idea trying to set preferredContentSize, but you're setting it on the wrong view. You should change the line
popoverPresentationController?.preferredContentSize = /* ... */
to:
myAlert.preferredContentSize = /* ... */
This should solve the problem.
I want to display an ActionSheet on both, iPhone and iPad devices. While my code works properly on iPhone's, it doesn't on iPad's. The reason for this is that I need to specify a location where to display the popover. As a result, I tried to used the code proposed in this answer. The problem that I currently have is, that I do not know how to pass the argument sender to the method.
For example, I have a UITableViewRowAction which when clicked should display the ActionSheet:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let rowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Action", handler:{action, indexpath in
print("Action for element #\(indexPath.row).");
self.displayActionSheet()
});
return [rowAction];
}
Which argument is sender in my case? I am not able to pass rowAction to displayActionSheet(), because the variable is used within its own initial value. I also tried to pass self.displayDeleteLicencePlateActionSheet(self.items[indexPath.row]), but same result – I always end up in the else clause of the guard expression:
guard let button = sender as? UIView else {
print("sender empty")
return
}
I want to display also an ActionSheet when clicking on an UIBarButtonItem:
let myButton = UIBarButtonItem(title: "FooBar", style: .Plain, target: self, action: #selector(SecondViewController.displaySecondActionSheet(_:)))
But same result. How can this be done?
Please refer following code to fix your issue.
TARGET_OBJECT will be your sender where from you want to show an alert.
func showAlert() {
let alert = UIAlertController(title: "Title", message: "Message text", preferredStyle: .alert)
let actionOK = UIAlertAction(title: "OK", style: .default) { (alertAction) in
}
alert.addAction(actionOK)
if let popoverController = alert.popoverPresentationController {
popoverController.sourceView = self.TARGET_OBJECT // TARGET_OBJECT will be your sender to show an alert from.
popoverController.sourceRect = CGRect(x: self.TARGET_OBJECT.frame.size.width/2, y: self.TARGET_OBJECT.frame.size.height/2, width: 0, height: 0)
}
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
}
Please check attached image it will appear as you want.