iOS UIAlertview with uitextview editable - ios

I'm searching for a way of putting an UITextView editable inside an UIAlertView.
I know how to put a simple textfield with :
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
But this isn't what i want. I want a bigger text input so a user can write a comment after a news for example.
Is this possible ?

Unfortunately what you are after isn't possible with a UIAlertView.
Apple don't allow developers to modify the view hierarchy of a UIAlertView or subclass it. Check out the Apple Documentation for UIAlertView. Under the section marked Subclassing note you will find
The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.
Unfortunately though because UIAlertView still has the addSubview: method so it contradicts what Apple are actually telling us but the reason this is still here is because UIAlertView is a subclass of UIView which has this method. So what Apple have done is they have overridden this method so that it does absolutely nothing so when you call [myAlertView addSubview:myView]; will do nothing and no view will be added to the UIAlertView.
So to get the behavior you are after you will need to implement a Custom AlertView (Check out Google search for Custom UIAlertView).
Fortunately in iOS 8 Apple introduced a new class called UIAlertController that allows you to get the behavior that you are after and they have deprecated the UIAlertView class.

Add a custom view into the alert view.
Change preferredStyle to .alert and .actionsheet as per the requirement.
func showPopUpWithTextView() {
let alertController = UIAlertController(title: "\n\n\n\n\n\n", message: nil, preferredStyle: .actionSheet)
let margin:CGFloat = 8.0
let rect = CGRect(x: margin, y: margin, width: alertController.view.bounds.size.width - margin * 4.0, height: 100.0)
let textView = UITextView(frame: rect)
textView.backgroundColor = .clear
alertController.view.addSubview(textView)
let submitAction = UIAlertAction(title: "Something", style: .default, handler: {(alert: UIAlertAction!) in print("Submit")
print(textView.text)
})
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {(alert: UIAlertAction!) in print("cancel")})
alertController.addAction(submitAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion:{})
}

Related

iOS Swift: UIAlertController ignores maximumContentSizeCategory

I'm trying to limit the dynamic text sizes of the UIAlertControllers in my app.
I have tried this:
let alertController = UIAlertController(title: "Test", message: nil, preferredStyle: .actionSheet)
alertController.view.maximumContentSizeCategory = UIContentSizeCategory.extraExtraExtraLarge
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alertController, animated: true, completion: nil)
but the maximumContentSizeCategory is ignored. How can I set a maximum dynamic font size for UIAlertController?
You can't customize a UIAlertController very much. Since it is just a presented view controller, simply write your own custom presented view controller whose view looks like an alert.

Why am I getting Nil Layout Anchor warning while presenting my custom UIAlert?

I have a custom UIAlert where I set the content view controller to my own custom VC. The alert functions properly, but I keep getting this error: "A constraint factory method was passed a nil layout anchor". I suspect it has something to do with how I am adding my subviews, but I have tried to constrain them to no avail. Here is the code:
let vc = UIViewController()
vc.preferredContentSize = CGSize(width: 250,height: 150)
let sortByPicker = UIPickerView(frame: CGRect(x: 0, y: 0, width: 250, height: 150))
sortByPicker.tag = 1
sortByPicker.delegate = self
sortByPicker.dataSource = self
vc.view.addSubview(sortByPicker)
let editRadiusAlert = UIAlertController(title: "Sort Projects By...", message: "", preferredStyle: UIAlertController.Style.alert)
editRadiusAlert.setValue(vc, forKey: "contentViewController")
editRadiusAlert.addAction(UIAlertAction(title: "Done", style: .default, handler: nil))
editRadiusAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(editRadiusAlert, animated: true)
That's probably because you set your contentViewController before the parent view controller (the alert controller) has been added to the view hierarchy.
As you probably know if you use this hack, contentViewController is a private property and you're not supposed to access / set it. If you do so, you shouldn't be surprised if things don't work as expected or suddenly break in the future.
If you really wanna go with it, I suggest you follow Leo Nathan's answer and subclass UIAlertController. If you then assign your contentViewController in viewDidLoad(), everything should be set up properly, including the parent's layout anchors.

Reposition UIAlertView

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

UIAlertController Slow to Appear and Dismiss - Swift

I am developing an iOS app, using Swift, and am having two issues with the UIAlertController being quite slow!
1 - Slow and jittery to appear
I have set up a UITableViewController, and when I tap a cell, it fires the following code:
let alertController = UIAlertController(title: "Enter Exam Grade", message: nil, preferredStyle:UIAlertControllerStyle.Alert)
alertController.addTextFieldWithConfigurationHandler({(textField: UITextField) in
textField.placeholder = "Earned"
textField.keyboardType = .NumberPad
})
alertController.addTextFieldWithConfigurationHandler({(textField: UITextField) in
textField.placeholder = "Out of"
textField.keyboardType = .NumberPad
})
alertController.addAction(UIAlertAction(title: "Save", style: UIAlertActionStyle.Default, handler: {
(alert: UIAlertAction) in
if let gradeTextField = alertController.textFields!.first as UITextField? {
if let outOfTextField = alertController.textFields!.last as UITextField? {
if (gradeTextField.text != "" && outOfTextField.text != "") {
print(gradeTextField.text)
print(outOfTextField.text)
}
}
}
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
When I navigate to the view, and tap the cell for the first time, I get a jittery and slow load of the alert, as you can see in the GIF below. Interestingly, subsequent taps load generally smoothly and quickly.
EDIT: The GIF has a framerate a little too slow, so I have attached some stills taken from a slowed down video of it:
a) First tap of "Grade Exam", the alert begins to appear in centre of the screen, but then shifts up (in a jolt) to the correct position).
b) Subsequent taps, the alert appears in the correct upper position from the beginning.
2 - Keyboard slow to dismiss when Alert dismisses
I have seen this issue all around StackOverflow, with no real satisfactory solutions. When you tap the Cancel button, the Alert will dismiss quickly, but then the keyboard takes a long time to dismiss also. This should be instantaneous, as the hanging keyboard leaves a bad impression with users.
The launching of your keyboard seems to be "normal" from the gif files you have provided. However assuming if it is slow, maybe you could try this if it does load faster.
Just to mention I've not tried this code and typing off from here.
For slow display of keyboard.
textField.placeholder = "Out of"
textField.keyboardType = .NumberPad
textField.becomeFirstResponder()
For slow hiding of keyboard.
alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: {
(alert: UIAlertAction) in
self.view.endEditing(true)
}))

Swift, iOS: How to use UIButton to trigger UIAlertController

I want to use an UIButton to trigger a UIAlertController... in Swift
So in this example I have an "Agree" button below some text, and I want the user to click Agree and have a pop-up alert with 2 options confirming/canceling the agreement. How would I go about connecting the UIButton and the UIAlertController. Also if the user cancels, I want the alert to dismiss and remain on the current VC. If the user agrees, I want it to segue to another view controller.
I fairly new to Swift, so if the answer could be detailed that would be extremely appreciated!
You need to add an IBAction (Control drag from your UIButton on your XIB/Storyboard, to the viewController implementation to link the button to the method). Inside the method that you link to the action you need to present the viewController, similar to the below:
func showAlert(sender: UIButton!)
{
var alert = UIAlertController(title: "Title", message: "Some Message", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Agree", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}

Resources