So I am neck deep in a project, and we kept running into this problem in multiple places throughout it. When we display a UIAlertView the standard, typical way, the title doesn't display on the alert, only the description and buttons. We do the initialization and display as anyone would:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Are you sure?" message:#"Deleting a ..." delegate:self cancelButtonTitle:#"Delete" otherButtonTitles:#"Cancel", nil];
[alert show];
Has anyone else ever run into this problem? We aren't importing and dependency that changes anything with that, nor are we doing anything that we can tell would cause this.
Edit: Here's an example of what I'm seeing:
I also met the same problem. The root cause is that I used "UIFont+Replacement" in my project. In iOS 7, system will use "UIFont fontWithDescriptor:" to setup font for labels in system controls.
I added a judgment to check whether the font replacement is used for system controls like UIAlertView. Please check my code, so far it works well:
UIFontDescriptor *replaceDescriptor = descriptor;
if (![descriptor.fontAttributes objectForKey#"NSCTFontUIUsageAttribute"]
|| ![((NSString *)[descriptor.fontAttributes objectForKey:#"NSCTFontUIUsageAttribute"])
isEqualToString:#"UICTFontUsageEmphasizeBody"])
{
NSString *replacementFontName = [replacementDictionary objectForKey:descriptor.postscriptName];
replaceDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementFontName size:pointSize];
}
return [self replacement_fontWithDescriptor:replaceDescriptor size:pointSize];
Related
I'm trying to implement an error popup function for iOS. My current implementation:
void SysErrorAlert(NSString * title, NSString * message, ...)
{
NSString * contents = nil;
va_list args;
va_start(args, message);
contents = [[NSString alloc] initWithFormat:message arguments:args];
va_end(args);
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:title
message:contents
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[alert show];
// tried this but popup still never shows...
//for (;;) { }
}
However, "[alert show]" is returning immediately without ever displaying the popup dialog.
I need the dialog to be displayed on top of the current application screen and block the calling thread until the user clicks one of the buttons. The application will them terminate after the function returns.
The app is running Cocos2d, so maybe the Cocos drawing is interfering with the UIAlertView... But I'm rather new to iOS programming and may be missing something obvious here.
NOTE: I have not tested this on an actual device, only in the simulator. Could it be a limitation/bug of the simulator?
Looks like you have to ask cocos2d for help to get the right parent for the alertview
This older post suggests an outline:
http://www.cocos2d-iphone.org/forums/topic/how-to-popup-a-uialertview-with-cocos2d/
This is my code
audioViewController *voiceRecorder = [audioViewController sharedManager];
[voiceRecorder stopRecording];
NSString *msg = [NSString stringWithFormat:#"Want to logout?"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Info"
message:msg
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
alert.tag = 100;
[alert show];
I am calling sharedManager in one of my view controller. The problem is, my alertview runs before sharedManager method executes, if you check my code, i have called "StopReording" method, but when i run the code, it works after showing alert. Anyone has idea, how do I show alert only after the method returns something.?
You seem to be confusing yourself about method run order and alert presentation order. The methods run in the order specified by your code, they must. What you see on screen is 2 alerts, one (stop) presented first, the the other (logout) presented immediately after.
Generally, you shouldn't show 2 alerts at the same time. Certainly not if they relate to different things.
Present your first alert, then wait for the answer to be received (using the delegate methods). Once you have the users answer, then decide what to do next and present the second alert or continue with some other operation.
I've been working with Facebook to make a multiplayer game. I want to allow the player to be able to invite his friends from Facebook to play in a match, so I use FBFriendPickerViewController for this. However, I want to limit the number of selected friends to a minimun of 1 player and a maximun of 4.
The problem is that there's no obvious way to do this, or at least none mentioned in the Developer documents at Facebook. I tried to prevent this inside
- (void)friendPickerViewControllerSelectionDidChange:(FBFriendPickerViewController *)friendPicker
but as the attribute NSArray *selection is readonly, it can't be done. I had also thought of warning the user after he had selected the friends and clicked the 'Done'button, but it's kind of lame allowing him to choose 100 friends and after that warning him about the 4 players max limit.
Does anyone have any idea how to do this? Or will I have to implement a full FBFriendPickerViewController from scratch?
Thanks! :D
One work around could be showing a label/message on the picker letting the user know they can pick up to 4 friends. Then after picking four you dismiss the view controller? Then you could add code like this:
- (void)friendPickerViewControllerSelectionDidChange:
(FBFriendPickerViewController *)friendPicker
{
if ([friendPicker.selection count] > 3) {
UIAlertView *alertView =
[[UIAlertView alloc] initWithTitle:#""
message:#"Max number of friends selected."
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self dismissModalViewControllerAnimated:YES];
}
You may be looking for a better experience, for example to give users a chance to edit from their maximum list. In that case you can get the source code from GitHub tableView:didSelectRowAtIndexPath: and tableView:didDeselectRowAtIndexPath: delegate methods in the FBGraphObjectTableSelection class. Looks like you would likely add a new "maxSelection" property and key off that.
Previous SDK was HTML based and was hosted on facebook but SDK 3.x is native iOS code with open source.
You can modify Facebook SDK. It is licensed under Apache license and add limit for friends you allow to invite.
just removing the friend picker isn't the solution! but this is!
i got it , after struggling for quite a few times.
solution was simpler than i imagined.
you friendPickerController is a tableView so we can set userInteractionEnabled property to NO.
- (void)friendPickerViewControllerSelectionDidChange:
(FBFriendPickerViewController *)friendPicker
{
if ([friendPicker.selection count] <=3)
{
self.friendPickerController.tableView.userInteractionEnabled=YES;
}
if ([friendPicker.selection count] >=3)
{
UIAlertView *maxFriendsAlert =
[[UIAlertView alloc] initWithTitle:#"Max number of friends selected."
message:#"no more friends can be selected,"
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:#"Buy more friends",nil];
[maxFriendsAlert show];
maxFriendsAlert.tag=1;
// disable friends selection
self.friendPickerController.tableView.userInteractionEnabled=NO;
}
Replying a bit late, but I was just looking for a solution to this issue, and I went with something that I found to be a bit cleaner than the other solutions listed:
- (void)friendPickerViewControllerSelectionDidChange:(FBFriendPickerViewController *)friendPicker {
if ([friendPicker.selection count] > 3) {
friendPicker.doneButton.enabled = NO;
[[[UIAlertView alloc] initWithTitle:#"Too many selections"
message:#"You may only select up to 3 friends."
delegate:nil
cancelButtonTitle:#"Ok" otherButtonTitles:nil] show];
} else {
friendPicker.doneButton.enabled = YES;
}
}
I inform the user that they have exceeded the max (via UIAlertView), then I disable the Done button. When the count comes back down to a valid number, I re-enable the Done button.
When the user presses my 'import' button, they must be able to type in a URL, which they can then 'ok' or 'cancel'.
How do I do this?
Obviously I could create a new view containing a text field and 2 buttons. But this seems like over coding.
One solution I found involves ' hacking ' a UITextField into a UIAlertView: http://iphone-dev-tips.alterplay.com/2009/12/username-and-password-uitextfields-in.html
(EDIT: Better -- http://www.iphonedevsdk.com/forum/iphone-sdk-development/1704-uitextfield-inside-uialertview.html#post10643 )
This looks really ugly. It is clearly a hack.
Can anyone provide a better solution (or even a better implementation of the same solution path)?
OK After a ton of digging, here is the result.
Firstly, putting in 'UITextField UIAlertView' into SO's search returns dozens of hits.
It turns out there is a method for doing this, Need new way to add a UITextField to a UIAlertView but it is private API :|
Pretty much every other solution involves hacking a UIAlertView, which is ugly:
http://junecloud.com/journal/code/displaying-a-password-or-text-entry-prompt-on-the-iphone.html
http://iphone-dev-tips.alterplay.com/2009/12/username-and-password-uitextfields-in.html
https://github.com/josecastillo/EGOTextFieldAlertView/
How to move the buttons in a UIAlertView to make room for an inserted UITextField?
^ MrGando's answer is neat
http://iphonedevelopment.blogspot.com/2009/02/alert-view-with-prompt.html
Getting text from UIAlertView
The only proper solution I found (ie coding from scratch from a UIView) is here: https://github.com/TomSwift/TSAlertView
This is all it takes:
- (IBAction) importTap
{
TSAlertView* av = [[[TSAlertView alloc] init] autorelease];
av.title = #"Enter URL";
av.message = #"";
[av addButtonWithTitle: #"Ok"];
[av addButtonWithTitle: #"Cancel"];
av.style = TSAlertViewStyleInput;
av.buttonLayout = TSAlertViewButtonLayoutNormal;
av.delegate = self;
av.inputTextField.text = #"http://";
[av show];
}
// after animation
- (void) alertView: (TSAlertView *) alertView
didDismissWithButtonIndex: (NSInteger) buttonIndex
{
// cancel
if( buttonIndex == 1 )
return;
LOG( #"Got: %#", alertView.inputTextField.text );
}
and Presto!
Check out: https://github.com/enormego/EGOTextFieldAlertView
I have created a post in my blog on the topic "How to add UITextField to UIAlertView from XIB". Using XIB to add is easier than pure coding. You can add whatever in a customized small view, then add the small view into the AlertView using 1 line code. Please refer to the following link.
http://creiapp.blogspot.com/2011/08/how-to-add-uitextfield-to-uialertview.html
Followup to Where is NSAlert.h in the iOS SDK?
Is there any way to get NSAlert runModal like behavior from a UIAlertView? Or from a UIActionSheet?
I'm planning on using only in debug builds so I'm not concerned with how it looks or if it uses undocumented functionality.
Edit:
NSAlert is part of the OS X SDK and is similar to MessageBox in Win32. It allows you to synchronously prompt the user for something. Here's an example:
NSAlert * myAlert=[[NSAlert alloc] init];
[myAlert setMessgeText:#"This is my alert"];
[myAlert addButtonWithTitle:#"button 1"];
[myAlert addButtonWithTitle:#"button 2"];
switch ([myAlert runModal]) {
case NSAlertFirstButtonReturn:
//handle first button
break;
case NSAlertSecondButtonReturn:
//handle second button
break;
}
runModal is a synchronous function, it shows the alert and waits for user response. Internally it is running a limited version of the message loop, but as far as the rest of my application is concerned, the world has stopped; no messages, no events, nothing.
Internally it is running a limited version of the message loop, but as far as the rest of my application is concerned, the world has stopped
Just do exactly what you described: throw up the alert, then run the event loop till the alert view gets dismissed. This code works:
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"O rlly?" message:nil delegate:nil
cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
NSRunLoop *rl = [NSRunLoop currentRunLoop];
NSDate *d;
while ([alert isVisible]) {
d = [[NSDate alloc] init];
[rl runUntilDate:d];
[d release];
}
[alert release];
You'll have to write your own if you want this behavior. Careful, if you block the main queue for too long, your app will be watchdog'd.
UIAlertView gives you modal behavior, and will end up working the same way your custom class will. You might consider using a block-based wrapper that wraps up UIAlertView and allows you to setup blocks for the button action callbacks.