I have a problem since iOS8 and Xcode 6.0.1, the title of my alert dialogs doesn't appear. So I changed my UIAlertView to UIAlertController but I have the same issue...
The title of my alert is always to nil and the displaying is very ugly because I don't have the serparator lines.
Do you know why i have this ?
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"title" message:#"message" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self dismissViewControllerAnimated:YES completion:nil];
}]];
[self presentViewController:alert animated:YES completion:nil];
But this is the result
(lldb) po alert.title
nil
(lldb) po alert.message
message
Thank you.
I resolved my problem thanks to #Myaaoonn !
UIAlertView title does not display
I have just Remove the following method from my ViewController
Category Class And its working fyn!
- (void)setTitle:(NSString *)title
{
// My Code
}
Try calling the UIAlertView like this:
[[[UIAlertView alloc] initWithTitle:<#title#>
message:<#msg#>
delegate:nil
cancelButtonTitle:<#cancel button#>
otherButtonTitles:<#buttons#>,nil] show];
Does the title still not show?
Related
I would like to present a UIAlertController with 2 buttons.
One button should close the alert and the second should perform an action but remain the alert on screen. Is there some configuration that can be done to action that it won't close the alert?
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"title"
message:#"message"
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:#"Do Something"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
//Pressing this button, should not remove alert from screen
}]];
[alert addAction:[UIAlertAction actionWithTitle:#"Close"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
//Regular functionality- pressing removes alert from screen
}]];
[alert show];
This (Prevent UIAlertController to dismiss) was suggested as possible answer, but the question deals with text field. I need one of the action buttons to not close the alert when pressed.
You can't do this.
Only one solution is to create a custom view controller that will look like native UIAlertController.
You can't do it with default UIAlertViewController, if you want to do this you need to create custom view controller whose look like UIAlertController.
You can use this custom view controller.
https://github.com/nealyoung/NYAlertViewController
Speaking from a user-perspective, a button press that doesn't follow through with an action would make me wonder if something was broken. If you're trying to use this as an opportunity to get further information, or some detail about the button press intention, I think a solution that adheres to user-expectation (though maybe a little annoying?) is to simply present a second dialog box after closing out the first. Basically, a "one-dialog-box-per-question" way of handling it.
Otherwise, I'll agree with the other suggestions and say that you need a custom view here, not a stock UIKit solution.
Try this code.
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"title"
message:#"message"
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:#"Do Something"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
NSLog(#"Do Something Tapped");
}]];
[alert addAction:[UIAlertAction actionWithTitle:#"Close"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
NSLog(#"Close Tapped");
}]];
[self presentViewController:alert animated:YES completion:nil];
How about this code:
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"title"
message:#"message"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *doSomethingAction = [UIAlertAction actionWithTitle:#"Do Something"
style:UIAlertActionStyleDefault
handler:nil];
doSomethingAction.enabled = NO;
[alert addAction:doSomethingAction];
[alert addAction:[UIAlertAction actionWithTitle:#"Close"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
//Regular functionality- pressing removes alert from screen
}]];
[self presentViewController:alert animated:true completion:nil];
set NO to enabled property of UIAlertAction. It works well.
I am working on a project that uses UIAlertView, now the problem is I have to replace all of the UIAlertView's with UIAlertController's and there are around 1250 of them in the code. I am planning to uses the existing Utility class to create a function that does this, following is what I am planning to do:
+(void)showAlert:(NSString *)title errorMessage:(NSString *)msg {
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
}
I have the following questions before doing this:
1 - Is this worth the efforts (Using UIAlertController instead of UIAlertView) ?
2 - How do I handle UIAlertView's that had tags and different delegate implementation across hundreds of files ?
3 - The fourth line the function above gives an error : No known class method for selector 'presentViewController:animated:completion:'
Any help is greatly appreciated.
You've to use UIAlertController as UIAlertView is deprecated.
Apple Doc says:
In apps that run in versions of iOS prior to iOS 8, use the
UIAlertView class to display an alert message to the user. An alert
view functions similar to but differs in appearance from an action
sheet (an instance of UIActionSheet). UIAlertView is deprecated in iOS
8. (Note that UIAlertViewDelegate is also deprecated.) To create and manage alerts in iOS 8 and later, instead use UIAlertController with a
preferredStyle of UIAlertControllerStyleAlert. Availability
Alternatively, you can do this way. In your Utils Class, do this:
+ (void)showAlertWithTitle:(NSString *)title message:(NSString *)msg controller:(id)controller {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:okAction];
[controller presentViewController:alertController animated:YES completion:nil];
}
Usage from your ViewController class:
[Utils showAlertWithTitle:#"Camera" message:#"It seems that your device doesn't support camera. " controller: self];
If your existing UIAlertView is having tags then you've to use the UIAlertViewController class instead of the Util method.
Hope it helps.
You can use a common alertcontroller class method. Here is an example how you can solve the no.4 error. Basically you pass also the viewController that wants to call the alertview.
+(UIImage *)showAlert:(NSString *)title errorMessage:(NSString *)msg inViewController:(id)vc {
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil]];
[vc presentViewController:alertController animated:YES completion:nil];
}
On the issue of alertviews with tags that require user input, to handle those inputs you might want to put the handler in and not let it nil and turn your method into a completionBlock method:
+(UIImage *)showAlert:(NSString *)title message:(NSString *)msg inViewController:(id)vc completedWithBtnStr:(void(^)(NSString* btnString))completedWithBtnStr {
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:#"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
completedWithBtnStr(#"Yes");
}]];
[alertController addAction:[UIAlertAction actionWithTitle:#"No" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
completedWithBtnStr(#"No");
}]];
[vc presentViewController:alertController animated:YES completion:nil];
}
An example of calling this is
[YourClass showAlert:#"Sure?" message:#"Delete this record?" inViewController:self completedWithBtnStr:^(NSString* btnString) {
if ([btnString isEqualToString:#"Yes"]) {
// delete record
}
}];
The parameter btnString can be anything really. The code is not tested so if you found error, do inform me.
Answering your questions:
It's definitely worth doing that. You have to use UIAlertController anyway in near future as of UIAlertview is deprecated.
Use blocks or protocol to get a callback when delegate methods in utility class are fired.
Looks like you are presenting that on NSObject. Present on view class. In this case, you can use window rootViewController to present on
+(void) showAlert
{
UIWindow* topWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
topWindow.rootViewController = [UIViewController new];
topWindow.windowLevel = UIWindowLevelAlert + 1;
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"title" message:#"message" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okButton = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Handle your yes please button action here
topWindow.hidden = YES;
//your ok button action handling
}];
[alertController addAction:okButton];
[topWindow makeKeyAndVisible];
[topWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
}
At the end of a process of doing backup I want to let the user know the backup is complete. I used to use UIAlertView, which works. However its depreciated so was swapping out these for UIAlertController. After the popup message is complete the window closes. The new UIAlertController doesnt seem to work in this situation. What am I doing wrong?
This is happening and the END of the process right before the view closes. The last line in the code below is closing the view. UIAlertView must be modal or something that stops the view from closing?
I used to use this code and it worked great.
UIAlertView *myalert = [[UIAlertView alloc] initWithTitle:nil message:Msg delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[myalert show];
[self presentViewController:alert animated:YES completion:nil];
And this new code you dont see anything
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:#""
message:Msg
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okButton = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
This line looks wrong:
[self dismissViewControllerAnimated:NO completion:nil];
Try removing that or putting it somewhere more suitable. I'd suggest that you are immediately presenting and then dismissing the alert.
[self dismissViewControllerAnimated:NO completion:nil];
Remove this line as you are presenting alert and quickly dismissing the View in which the alert was presented.
In short you are showing alert and removing the view on which the alert was shown
With the latest iOS 8.3 release, our app starts to have a weird behavior.
After finishing textfield editing, the user can click the close button which brings up an UIAlertView. When the user clicks discard in the alertview, alertview and current view are dismissed. But somehow the keyboard shows up after the view is gone which is quite annoying to users.
After some debugging, it seems that the keyboard is shown for the last textfield that the user has accessed before closing the view. I tried various ways to endEditing for the current view in many places (before showing UIAlertView, after clicking a button in the UIAlertView; I even set the focus to another UI element of the view). It didn't solve the problem.
But for this particular issue, I'm not sure if it's a common issue or something we need to fix. Everything works perfectly before iOS 8.3.
We understand that UIAlertView is deprecated for iOS 8. We're starting to migrate to UIAlertController. But if there's any workaround, we'd love to hear.
Here's some code snippet.
- (IBAction)closeTapped:(UIButton *)sender
{
// try to resign first responder
// [self.tfName resignFirstResponder];
// [self.tfPosition resignFirstResponder];
[self.view endEditing:YES];
if(self.orderDetails.isOpen && self.orderItemChanged)
{
UIAlertView* saveAlert = [[UIAlertView alloc] initWithTitle:#"Unsaved Changes"
message:#"Your changes have not been saved. Discard changes?"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Save", #"Discard", nil];
[saveAlert show];
}
else
{
[self close];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch(buttonIndex)
{
case 1: // Save
{
[self save];
break;
}
case 2: // Discard
{
[self close];
break;
}
}
}
- (void)close
{
[self.delegate dismissEditOrderItemVC];
}
If your deployment target is iOS 8+, try UIAlertController.
Here's a quick fix for UIAlertView: delay the invocation of showing the alert view when your text field or text view resigns first responder.
[self performSelector:#selector(showAlertView) withObject:nil afterDelay:0.6];
If anyone struggles with this, I hope this will help:
if (NSClassFromString(#"UIAlertController")) {
UIAlertController* alert = ...
}
else {
UIAlertView* alert = ...
}
you need to change alert for ios 8.3
first put this in your view
#define IS_IOS8 [[UIDevice currentDevice].systemVersion floatValue] >= 8.0
then
if (IS_IOS8) {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:#"Unsaved Changes" message:#"Your changes have not been saved. Discard changes?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *saveAction = [UIAlertAction
actionWithTitle:#"Save"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
[self save];
}];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
[alertVC dismissViewControllerAnimated:YES completion:nil];
}];
UIAlertAction *discardAction = [UIAlertAction
actionWithTitle:#"Discard"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
[alertVC dismissViewControllerAnimated:YES completion:nil];
}];
[alertVC addAction:saveAction];
[alertVC addAction:cancelAction];
[alertVC addAction:discardAction];
[self.view.window.rootViewController presentViewController:alertVC animated:YES completion:nil];
this will help you as it helps me in same problem.
above code is compatible with both ios 7 & 8
I too, had a keyboard popping up (with the cursor in the last-used textView) after closing a UIAlertController and here is a very simple fix:
Immediately before building and presenting the UIAlertController,
Using [_activeTextView resignFirstResponder]; the keyboard will reappear.
Using [self.view endEditing:YES]; the keyboard will NOT reappear.
I hope this helps you.
Try using the below code. It works fine for iOS 8 and below version
if (IS_OS_8_OR_LATER) {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
}];
[alertVC addAction:cancelAction];
[[[[[UIApplication sharedApplication] windows] objectAtIndex:0] rootViewController] presentViewController:alertVC animated:YES completion:^{
}];
}
else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
}
If a text field is the first responder, it will automatically pop up the keyboard when the alert is dismissed. Ensure the first responder is properly dismissed with:
[textField resignFirstResponder]
Remember: in a table or scroll view, sometimes the field must be visible on the screen to properly dismiss the responder.
If there are no first responders active, keyboard should not appear when alert is dismissed.
For the particular case in this question, I would recommend setting a delegate method to listen for the "done" button and resigning the first responder in the delegate callback.
Alternatively, when beginning editing, you can store a reference to the currently active text field, then in your "clickedButtonAtIndex" method you can resign the active text field if it is still active.
I've noticed some weird behavior with textField keyboards and alertViews as well... Maybe make a bool called disableKeyboard and use it like this:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if (disableKeyBoard) {
disableKeyboard = NO;
return NO;
} else {
return YES;
}
}
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
disableKeyboard = YES;
}
This is just a workaround and doesn't address the core issue, whatever it is. For this method to work you need to set the alertView and textField delegate methods in your header.
I am trying to understand a weird behavior of my app, here is a description (tested in a trivial project).
ViewControllerA is presenting modally ViewControllerB
ViewControllerB contains a button, this button is presenting a UIAlertController specified this way
alert = [UIAlertController alertControllerWithTitle:#"Test" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[alert addAction:[UIAlertAction actionWithTitle:#"Action" style:UIAlertActionStyleDefault handler:^(UIAlertAction *handler) { NSLog(#"Action"); }]];
The ViewControllerB is presenting alert this way
- (IBAction)button:(id)sender {
alert.popoverPresentationController.sourceView = self.button;
alert.popoverPresentationController.sourceRect = self.button.bounds;
[self presentViewController:alert animated:YES completion:nil];
}
Now, if you click on the button, the alert appears, if you click outside the alert, the alert disappears (I am on iPad). You can do it as many times as you want...
Here is the bug: When the alert is presented, if you click twice outside (quickly enough, ~0,2s interval), the alert disappears AND ViewControllerB is dismissed. At the end we can see ViewControllerA but we never asked for it.
There is also a warning message:
Warning: Attempt to dismiss from view controller <UIViewController: 0x7f85ab633f70> while a presentation or dismiss is in progress!
Thank you for your help.
I would prefer to add a UITapGestureRecognizer at the end, on your UIAlertController. like :
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Test"
message:#"Test Message."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *closeAction = [UIAlertAction actionWithTitle:#"Close"
style:UIAlertActionStyleDefault
handler:nil];
UIAlertAction *someAction = [UIAlertAction actionWithTitle:#"Action"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
....
}];
[alertController addAction:closeAction];
[alertController addAction:someAction];
[self presentViewController:alertController animated:YES completion:^{
[alertController.view.superview addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget: self action:nil]];
}];