So I've upgraded the code to the ipad (i.e. converted to a universal app). However, the UIAlertview rendering seems to be off for IOS4. Instead of being positioned in the middle, it jumps up and is displayed on top, with half the box cut off. Same goes for landscape orientation.
It is my understanding that the UIalertview is always set in the middle? I looked through the code and I did not set up the frame/position anywhere in the code. This only happens for 4.0, on both the iphone 4 and the itouch running 4.0. Every other version is fine, including the ipad. Any thoughts?
Thanks.
Seems to be a bug. I also had the Problem on iPad with iOS 3.2.
Solution:
a) Check your app state:
In iOS 4 just use
[UIApplication sharedApplication].applicationState
Older iOS: Store your app state manually:
-(void)applicationWillResignActive:(UIApplication *)application
{
self.appIsInBackground = YES;
}
-(void)applicationWillTerminate:(UIApplication *)application
{
self.appIsInBackground = YES;
}
-(void)applicationDidBecomeActive:(UIApplication *)application
{
// Open your UIAlert here if self.appIsInBackground == YES;
self.appIsInBackground = NO;
}
b) open the UIAlert after the app did become active, as shown above in the comments.
Does your alert have any Textfields added ?
Because in 4.0+ iOS scrolls the alertview to visible part if you have a textfield in the alertview.
I have the same problem for iPad 3.2 when application resign active and in that time alert is shown that alert will be shown on top left corner. So i fixed using following code in the method -(void)applicationDidBecomeActive:(UIApplication *)application
//Check that key window is alert view
if ([[[UIApplication sharedApplication].keyWindow description] hasPrefix:#"<_UIAlertOverlayWindow"]) {
//Yes then check for subviews tht are alertViews
UIWindow *alertViewWindow = [UIApplication sharedApplication].keyWindow;
NSArray *subViews = [alertViewWindow subviews];
for (UIView *subview in subViews)
{
if ([subview isKindOfClass:[UIAlertView class]])
{
//Retain it
UIAlertView *alertView = (UIAlertView *)[subview retain];
//Now dismiss it and then show it again
[alertView dismissWithClickedButtonIndex:0 animated:NO];//Here ClickedButtonIndex must be according to cancel button
//Show the alert view again
[alertView show];
//Release previsous retained object
[alertView release];
}
}
}
Related
I have a simple view with a button linked with "showAlert" method. When I click on this button, it displays a UIAlertView.
Before, with ios 6, I was using the following code to disable a UIAlertView button :
- (IBAction)showAlert:(id)sender
{
myAlert = [[UIAlertView alloc] initWithTitle:#"" message:#"" delegate:self cancelButtonTitle:#"Retour" otherButtonTitles:#"Button1", #"Button2", #"Button3", #"Button4", nil];
[myAlert show];
for(UIView *aView in myAlert.subviews)
{
if ([[[aView class] description] isEqualToString:#"UIAlertButton"])
{
UIButton *aButton = (UIButton *)aView;
if ([aButton.titleLabel.text isEqualToString:#"Button2"])
aButton.enabled = NO;
}
}
}
Now, with ios 7, it does not work... Why ?
Since iOS7 it's not possible to add or manipulate the subviews or a UIAlertView, you need to create your own, sorry.
Subclass UIView to create your own UIAlertView or use a 3rd party library.
Adding a subview to UIAlertView is not possible from iOS 7.
The only way is to go for a custom UIView subclass which can act as UIAlertView.
Github and this answer may get you a solution.
You can disable 1st other Button of UIAlertView using delegate method
-(BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
return NO;
}
works in ios 7 also.
For a specific server notification I am supposed to show an UIActionSheet. But problem here is when that event comes, at the same time if any UIAlertView already showing on any view controller, it make the UIActionSheet disabled( After pressed ok for alert view I am not able to select anything on view controller , view got disabled because of UIActionSheet). Anyone faced this kind of problem, Any idea how to solve it?
I have tried by dismissing alert view before showing action sheet, however which alert view do I need to dismiss as I have many alert view in many controller. All are local to that controllers. How to solve this problem.
Note:
Same problem won't come for iPod, as it wont allow to click ok before responding to UIActionSheet.
Take a Global Alert view named it as activeAlertView. Now when you show a alert view please check that alert view and then show and assign. Like
declare a property in .h and synthesize it
#property (nonatomic, retain) UIAlertView *activeAlertView;
then use the below code when try to show an alert.
if(self.activeAlertView){
[self.activeAlertView dismissWithClickedButtonIndex:0 animated:YES];
}
UIAlertView *localAlert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Your message" delegate:nil cancelButtonTitle:#"cancel" otherButtonTitles:nil, nil ];
[localAlert show];
self.activeAlertView = localAlert;
[localAlert release];
this way your activeAlertview will keep the current aler view's reference and before show the actionSheet dismiss the alert view.
For Identified which alert-view you must set Tag or alert-view.
Ex:-
alertviewName.tag=1;
Then you can check is there alert-view Open in Particular view-controller sub-views use bellow code like:-
- (BOOL) doesAlertViewExist {
for (UIView* view in yuorviewcontroller.view.subviews) {
BOOL alert = [view isKindOfClass:[UIAlertView class]];
if (alert)
{
return YES;
}
}
return NO;
}
After this method called you get BOOL value YES or NO If Yes then dismiss it using UIAlertview's Delegate:-
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;
and put your Actionsheet appear code into didDismissWithButtonIndex method.
When the message comes, first check if there is an alert view.
Show the action sheet after the alert view is dismissed. In didDismiss... you can check a BOOL flag if you now have to show the action sheet or not.
In this case, you should use
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
method rather than,
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
so your code wil be:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
UIActionSheet *actionSheet = ...
[actionSheet showFromTabBar:self.tabBarController.tabBar];
}
}
Thanks
try this:
for (UIWindow* w in [UIApplication sharedApplication].windows)
{
for (NSObject* obj in w.subviews)
{
if ([obj isKindOfClass:[UIAlertView class]])
{
[(UIAlertView*)obj dismissWithClickedButtonIndex:[(UIAlertView*)obj
cancelButtonIndex] animated:YES];
}
}
}
My iPhone app is design to support portrait orientation only, except one view controller that present photos, and support landscape mode as well.
So overall my project support all the orientations, but every view controller (except the photo view controller) implement the method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
The problem:
In one of my (only portrait) view controller, I'm using UIActivityViewController to let the user choose sharing content through email or SMS.
When the user pick the email option, it automatically shows the ios native email view controller.
If the user now change the device's orientation to landscape, the email view controller also changes to landscape, now if the user tap the cancel/send button, the email controller get dismissed, and now my all app is in landscape!
Is there a way to force the eamil view controller to be in portrait mode only?
I know I can create my own email view controller and subclass UIActivity to show it, but than the UIActivityViewController won't show the default email icon when presented, and I really like it to show it and not some other (must be grey) icon that I'll provide.
You should make another uinavigationcontroller and present uiactivityviewcontroller from there.
In this code _image is a UIImage yo wan to share.
BlankViewController is just place holder viewcontroller you can create in IB you can also make it's view's background colour to clear and do what ever appearance changes you want to do.
__weak CurrentViewController *weakSelf = self ;
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[_image] applicationActivities:nil] ;
UIViewController *viewC = [[UIViewController alloc] initWithNibName:#"BlankViewController" bundle:nil] ;
UINavigationController *navC = [[UINavigationController alloc] initWithRootViewController:viewC] ;
activityViewController.completionHandler = ^(NSString *activityType, BOOL completed)
{
[weakSelf dismissViewControllerAnimated:NO completion: ^ {
; // Your completion handler
}] ;
};
[self presentViewController:navC animated:NO completion: ^ {
[navC presentViewController:activityViewController animated:YES completion: ^ {
;
}] ;
}];
i had similar problems in the app i am currently developing. i ended up overwriting more of the rotation methods to make sure my own viewcontroller stays in portrait.
that's what worked for me (IOS5+):
- (BOOL) shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
if you are pre ios5 or that's not working for you have a look at:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
hope you get it to work. :)
May be u should try
- (void)viewWillAppear:(BOOL)animated
{
[self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight];
[super viewWillAppear:animated];
}
on your view?
Couldn't found a solution to this problem, so I ended up implementing my own email UIActivity subclass...
In my app I have an action sheet and one of its buttons opens the TWTweetComposeViewController modally. On iPhone simulator the cancel button on the tweet composer works fine and dismisses the view. However, on iPad simulator the cancel button does not work and the tweet composer view remains on the screen. It is even weirder because after pressing the cancel button, the keyboard retracts and the underlying views become active. It behaves as if the view has been dismissed but its is still there.
The code I used when the user pressed the action button is:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"Open in Safari"]){
[[UIApplication sharedApplication] openURL:[self.webView.request URL]];
}else if ([buttonTitle isEqualToString:#"Twitter"]){
if ([TWTweetComposeViewController canSendTweet]){
TWTweetComposeViewController *tweetSheet = [[TWTweetComposeViewController alloc] init];
[tweetSheet addURL:[self.webView.request URL]];
tweetSheet.completionHandler = ^(TWTweetComposeViewControllerResult result){
if (result == TWTweetComposeViewControllerResultCancelled){
[self dismissModalViewControllerAnimated:YES];
}
};
[self presentModalViewController:tweetSheet animated:YES];
}else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Twitter error" message:#"You can't send a tweet right now, make sure your device has an internet connection and you have at least one Twitter account setup" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
}
Do you have any idea on how to solve this problem or is it a bug of the simulator?
P.S.: My app is a tabbar app and this code is called from one of of the view controller of the tab bar.
I'm having this same problem on the actual device. It turns out this is a bug in Apple's SDK for TWTweetComposeViewController.
See the bug report here on OpenRadar: http://openradar.appspot.com/radar?id=1484405.
When a completionHandler block is added to
TWTweetComposeViewController, the completion handler needs to call
-[UIViewController dismissModalViewControllerAnimated:], even though the view for the tweet composer dismisses itself with its cancel or
send buttons. Failure to do so causes touch events to not reach the
view that spawned the tweet composer.
Just thought I'd add how I'm doing things, even though this is not correctly following memory guidelines, it's a workaround:
[compose setCompletionHandler:^(TWTweetComposeViewControllerResult result){
dispatch_async(dispatch_get_main_queue(), ^{
if(self.delegate != nil)
{
if (result == TWTweetComposeViewControllerResultDone)
{
[self.delegate twitterOperation:TETwitterOperationTweet
completedSuccessfully:YES
withResponseString:#"Tweet Successful"];
}
else if(result == TWTweetComposeViewControllerResultCancelled)
{
[self.delegate twitterOperation:TETwitterOperationTweet
completedSuccessfully:NO
withResponseString:#"Tweet Cancelled"];
}
}
// Dismiss per Apple's Twitter example
[self.shownInViewController dismissViewControllerAnimated:YES
completion:nil];
// Yuck. But it's necessary.
[compose release];
});
I am having a weird issue with my keyboard automatically closing and then reopening when I open multiple UIAlertViews. If I have a keyboard (from a separate UITextField) and I display a UIAlertView, then upon dismissal of that alert I open another (opening the second one in the didDismissWithButtonIndex). When I dismiss the 2nd one it dismisses the keyboard which then comes back up. If i try this with more than 2 alerts in a row, it will still close my keyboard after the 2nd alert is dismissed, but it doesn't show up until the last alert is dismissed. The problem is that the keyboard delegate functions are NOT called so I cannot respond to it being dismissed. I have other UI elements (textfield and images) that get shifted when the keyboard opens, so when it closes those elements float in the screen and look strange. Any idea why that keyboard automatically dismisses? Thanks
BTW, I use an NSMutableArray of NSDictionary objects to queue up alerts that need to be displayed if an alert is already displayed. I am not creating and displaying more than 1 alert at a time.
EDIT: Here's sample code. If you run this you'll see both alerts open (0 then 1) after you dismiss '1' you'll see '0' under it. After you dismiss '0' you'll see what I mean - they keyboard briefly closes and opens but no delegate functions are called. If you set i to a value higher than 2, you'll see that the keyboard still closes after dismissing the 2nd alert, but will stay closed until the last alert is dismissed. I also tried opening just 1 UIAlert, and opening the others one at a time from a queue as each one was dismissed, and still noticed that same behavior. Any ideas?
EDIT: After some more digging I found that if I register for the notifications UIKeyboardDidShowNotification and UIKeyboardDidHideNotification they are in fact fired when the keyboard is automatically dismissed and presented. I still would like to know what in the underlying API is causing it to even happen so it can hopefully be avoided.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 100, 320, 48)];
[textField setDelegate:self];
[textField setBackgroundColor:[UIColor redColor]];
[window addSubview:textField];
[textField release];
[self.window makeKeyAndVisible];
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *) textField{
NSLog(#"textFieldShouldReturn called with %#", textField);
[textField resignFirstResponder];
return YES;
}
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(#"textFieldDidBeginEditing called with %#", textField);
for (int i=0; i< 2; i++) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"test" message: [NSString stringWithFormat:#"%d", i] delegate:self cancelButtonTitle:NSLocalizedString(#"OK",#"") otherButtonTitles:nil];
[alert show];
[alert release];
}
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
NSLog(#"++++ textFieldShouldEndEditing %#", textField);
return YES;
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
NSLog(#"++++ textFieldDidEndEditing %#", textField);
}
the keyboard is only shown when the corresponding UI element is the first responder.. somehow multiple alert views modify the responder chain for a short time. Seems like a framework issue..
I would suggest this workaround:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
dispatch_async(dispatch_get_main_queue(), ^{
/* show new alert view here */
});
}
EDIT
actually i now think it has to do with the Window hierarchy of the application. UIAlertViews create their own window (at window level UIWindowLevelAlert), make them the key window to recieve touch input and then make the old window key window again upon dismissal. When you show a new alert view on didDismiss, UIKit seems to lose (temporarily) track of key windows and the responder chain..
The fix above of course still applies.