Action Sheet picker on Button IOS - ios

HeyI want to do that This my button and in button there is textfield I want to do that when I pressed on button the action sheet picker become appear and give 4 to 5 list of string whatever I select it will apear on textfield which is in button. please help me

Start by adding a target for your button. In Objective-C, that would be like this:
[myButton addTarget:self
action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
Then create the method buttonPressed. An example of that would be:
- (void)buttonPressed:(id)sender {
if ([sender isEqual:self.myButton]) {
//This is where you can create the UIAlertController
}
}
Then, to create the UIAlertController:
UIAlertController *myAlertController = [UIAlertController alertControllerWithTitle:#"Title"
message:#"Message"
preferredStyle:UIAlertControllerStyleActionSheet];
Then you create actions for what each button you want to have appear on the action sheet. You need to have a title for the button and an action for them, though the action block can be empty.
UIAlertAction *action1 = [UIAlertAction actionWithTitle:#"Action 1"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
//Whatever you want to have happen when the button is pressed
}];
[myAlertController addAction:action1];
//repeat for all subsequent actions...
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(#"Cancel", nil)
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
// It's good practice to give the user an option to do nothing, but not necessary
}];
[myAlertController addAction:cancelAction];
Lastly, you present the UIAlertController:
[self presentViewController:myAlertController
animated:YES
completion:^{
}];
NOTE:
If you're building for iPad and using an Action Sheet style for the UIAlertController, then you will need to set a source for the UIAlertController to present from. This can be done like this:
if ([sender isKindOfClass:[UIView class]]) {
if ([myAlertController.popoverPresentationController respondsToSelector:#selector(setSourceView:)]) { // Check for availability of this method
myAlertController.popoverPresentationController.sourceView = self.myButton;
} else {
myAlertController.popoverPresentationController.sourceRect = self.myButton.frame;
}
}

Related

ios Keyboard must not show up automatically for a UITextField in UIAlertController

I am trying to show UIAlertController with text field. When it launches keyfoard automatically shows up as textfield get the focus automatically. How can I show alert with textfield without keyboard (it should show up only when user clicks on textfield).
Here is my code
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Collect Input" message:#"input message"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"Submit" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//use alert.textFields[0].text
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:#"Cancel" handler:^(UIAlertAction * action) {
//cancel action
}];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
// A block for configuring the text field prior to displaying the alert
//[textField resignFirstResponder];
}];
[alert addAction:defaultAction];
[alert addAction:cancelAction];
[self presentViewController:alert animated:NO completion:nil];
There are a few solutions.
You can get a reference to the text field in the addTextFieldWithConfigurationHandler callback and store it in a local variable. Then in the completion handler of presentViewController you can call resignFirstResponder on the text field. But this solution is far from ideal because the keyboard will appear and then immediately be dismissed.
Better yet is to set the text field's delegate and implement the shouldBeginEditing delegate method. Add an instance variable to act as a flag. The first time shouldBeginEditing is called, not the flag isn't set, set it, and return NO. Then each time after, check the flag and return YES.
Here's the implementation for option 2:
Indicate that your class conforms to the UITextFieldDelegate protocol in the .m file:
#interface YourClassHere () <UITextFieldDelegate>
#end
Add an instance variable for the flag:
BOOL showKeyboard = NO;
Update your alert setup code to set the text field's delegate:
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.delegate = self;
}];
Implement the text field delegate method:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if (showKeyboard) {
return YES;
} else {
showKeyboard = YES;
return NO;
}
}
This prevents the initial display of the keyboard but allows it any time after that.

UIAlertAction - Edit UIAlertAction after it was set

I have a class named ManagerClass.
Manager Class has a function showUIAlertController:
- (UIAlertController*)showUIAlertController:(NSString *)title message:(NSString *)message actions:(NSArray<UIAlertAction*>* )actions
This function should show alert controller with the parameters received.
So far so good...
Now i would like to take these actions and edit them somehow. Something like:
UIAlertAction *action = actions.firstObject;
UIAlertAction *actionCopyWithAdditionalAction = [UIAlertAction actionWithTitle:action.title style:action.style handler:^(UIAlertAction * _Nonnull action) {
[action "performTheAction"]; //perform the original action
[ManagerClass doSomething];
}];
"performTheAction" does not exist - it is just for you to understand what i am trying to achieve.
Does anyone has an idea how this task can be achieved ?
Did not find a way to do that while looking at Apple's UIAlertAction API
https://developer.apple.com/reference/uikit/uialertaction
Do you mean to perform a method provided by your code. Then use:
[self performSelector:#selector(aMethod:)];
or when sending an object with:
[self performSelector:#selector(aMethod:)
withObject:(id)object];
Note, the self here is referencing to the same class, it could be somewhere else as well.
Edit *
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"My Alert"
message:#"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"42.");
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
The console logs out 42. Put instead every action do you need.
Why you want to call a second alert which only displays the first alert and execute some of your code? You can do that in the first alert, too.
//Create the UIAlertController
UIAlertController *theAlertController = [UIAlertController alertControllerWithTitle:#"Your Title" message:#"Your Message" preferredStyle:UIAlertControllerStyleAlert];
//Add an UIAlertAction which the user can click at
[theAlertController addAction:[UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
//Execute your own code
//[self myOwnCode];
//Close the AlertController after your code
[self dismissViewControllerAnimated:YES completion:nil];
}]];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:theAlertController animated:YES completion:nil];
});
Hope i understand you right.
You could pass a alert action model instead of a UIAlertAction.
so your method would look something like this:
- (UIAlertController*)showUIAlertController:(NSString *)title message:(NSString *)message actions:(NSArray<MyActionModel*>* )actions
where MyActionModel is a class with 3 properties
#interface MyActionModel: NSObject {
#property NSString * title;
#property UIAlertActionStyle * style;
#property ((void)^(UIAlertAction *)) action;
}
Then you can create your UIAlertActions when you need them and also add in your manager callbacks.
P.S. Sorry if my Objective-C is not quite right, I'm a bit rusty.

UIAlertController is nil when handler block executes

Here's the problem up front: I have a UIAlertController that has a textfield. I want to save the content of that textfield as an NSString when the user touches a "Confirm" button in the alert. When the Confirm action block is executed, however, the alert is nil (presumably already dismissed and deallocated at that point), and thus so is its textfield, meaning I cannot save the textfield's text.
I am using a series of UIAlertControllers to allow a user to create a passcode for my app, such that any time the app comes to the foreground, the user is prompted for the code before the app can be used.
I created a category of UIAlertController with several convenience methods that return preconfigured alerts that I need to use. Here's one of them:
+ (UIAlertController*)passcodeCreationAlertWithConfirmBehavior:(void(^)())confirmBlock andCancelBehavior:(void(^)())cancelBlock {
UIAlertController *passcodeCreationAlert = [UIAlertController alertControllerWithTitle:#"Enter a passcode"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
[passcodeCreationAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.keyboardType = UIKeyboardTypeNumberPad;
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (cancelBlock) {
cancelBlock();
}
}];
UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:#"Confirm"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (confirmBlock) {
confirmBlock();
}
}];
[passcodeCreationAlert addAction:cancelAction];
[passcodeCreationAlert addAction:confirmAction];
passcodeCreationAlert.preferredAction = confirmAction;
confirmAction.enabled = NO;
return passcodeCreationAlert;
}
This method returns a UIAlertController that allows the user to enter their desired passcode into a textfield. When I call this method in my view controller, I pass blocks as parameters which are used as the UIAlertAction handlers:
- (void)presentCreatePasscodeAlert {
UIAlertController *alert = [UIAlertController passcodeCreationAlertWithConfirmBehavior:^{
firstPasscode = alert.textFields[0].text;
[self presentConfirmPasscodeAlert];
} andCancelBehavior:^{
[self presentEnablePasscodeAlert];
}];
alert.textFields[0].delegate = self;
[self presentViewController:alert animated:YES completion:nil];
}
To reiterate the problem now that there is more context: When the action block is entered at the line:
firstPasscode = alert.textFields[0].text;
the alert is nil, and so is its textfield, meaning I cannot save the textfield's text.
In a separate project, however, I tried getting the same functionality without using the category and custom convenience methods, and that works as desired:
- (void) createPassword {
UIAlertController *createPasswordAlert = [UIAlertController alertControllerWithTitle:#"Enter a password"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
__weak ViewController *weakSelf = self;
[createPasswordAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.delegate = weakSelf;
textField.keyboardType = UIKeyboardTypeNumberPad;
}];
UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:#"Confirm"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
self.password = createPasswordAlert.textFields[0].text;
[self confirmPassword];
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:#"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self promptPasswordCreation];
}];
[createPasswordAlert addAction:confirmAction];
[createPasswordAlert addAction:cancelAction];
confirmAction.enabled = NO;
[self presentViewController:createPasswordAlert animated:YES completion:nil];
}
Sure enough, in the above code the alert exists when the Confirm block is entered, and I can save the text just fine.
Have I done something screwy by passing blocks as parameters to my convenience methods?
One of your problems is that when you create the block and send it into the initializer you are referencing a nil object inside the block. Then the block is saved with that nil reference and passed as a block to your handler.
UIAlertController *alert = [UIAlertController passcodeCreationAlertWithConfirmBehavior:^{
firstPasscode = alert.textFields[0].text;
[self presentConfirmPasscodeAlert];
} andCancelBehavior:^{
[self presentEnablePasscodeAlert];
}];
In there alert is not initialized yet when you create that block and send it to be saved. An option to fix that would be to use a standard initializer and then categorize a method to add the block functions that you want. Another option might be to try to add the __block modifier to the alert object, although I don't think that will help.

UIAlerController Action Sheet does not respond the second time it's called

I have something like the following code. The Action sheet runs doSomething OK when it appears for the first time (in a button IBAction), but when it appears the second time, nothing happens the Action sheet just disappear without calling do something. Any idea?
#implementation ...
- (void) setActions {
UIAlertAction *opt1 = [UIAlertAction actionWithTitle:#"Option 1" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self doSomething:#"opt1"];}];
UIAlertAction *opt2 = [UIAlertAction actionWithTitle:#"Option 2" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self doSomething:#"opt2"];}];
UIAlertAction *opt3 = ...
self.opt1 = opt1;
self.opt2 = opt2;
self.opt3 = opt3;
- (void) showActionSheet {
...
UIAlertController *selectAS = [UIAlertController alertControllerWithTitle:#"Select Options"
message:#"msg" preferredStyle:UIAlertControllerStyleActionSheet];
if (xyz) {
[selectAS addAction:self.opt1];
[selectAS addAction:self.opt2];
}
else{
[selectAS addAction:self.opt1];
[selectAS addAction:self.opt3];
}
[self presentViewController:selectqAS
animated:YES completion:nil];
}
- (void) doSomething: (NSString *) opt{
....
}
Glad we got you up and running. My guess is your methods are getting lost in translation. You have methods intertwining each other which can be causing the confusion, specifically with self.opt1. per my comment, now that iOS8 has introduced UIAlertController, it comes with completion handlers, you should plan accordingly to that: something like the following :
-(IBAction)showActionSheet {
UIAlertController *selectAS = [UIAlertController alertControllerWithTitle:#"Select Options" message:#"msg" preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *opt1 = [UIAlertAction actionWithTitle:#"Option 1" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
//Don't have to call another method, just put your action 1 code here. This is the power of completion handlers creating a more structured outline
}];
UIAlertAction *opt2 = [UIAlertAction actionWithTitle:#"Option 2" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
//Don't have to call another method, just put your action 2 code here. This is the power of completion handlers creating a more structured outline
}];
UIAlertAction *opt3 = ...
if (xyz) {
[selectAs addAction:opt1];
[selectAs addAction:opt2];
} else {
[selectAs addAction:opt1];
[selectAs addAction:opt3];
}
[self presentViewController:selectAs animated:YES completion:nil];
}
Much more cleaner and actually uses the UIAlertController for it's intended purposes, no other method calls needed.

How to stop AlertView from showing up by adding "Don't show again" button?

I have an application with an alertview that shows up when the application launches to explain about the app function.
On my alertView I want to make "Don't show again" button, so the user doesn't have to see the same alert every time he/she uses my app.
So how can I stop the alertView from showing up after the user selects this button. Should I work on the appDelegate or should I work on the viewcontroller where my alertview will pop up?
I would store a value in NSDefault for this, as we cannot change this on UIAlertView.
So once the UIAlertView has shown, set this value to something that represents "read", retrieve it in one of the App Delegate methods such as applicationDidBecomeActive and use it as a condition in a if statement for displaying the UIAlertView.
Let say you had an NSInteger = 0, which signifies "unread", once the UIAlertView is shown, set it to 1 and store it in NSDefault.
if(alertHasBeenRead == 0)
{
//bring up alert view
}
And subsequently in one of the delegate callback, set this value to something else other than 0, for example.
Hope this helps.
Try this:
if (![#"1" isEqualToString:[[NSUserDefaults standardUserDefaults] objectForKey:#"alert"]]){
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:NSLocalizedString(#"Information", #"The title of an alert.")
message:NSLocalizedString(#"Some text goes here.", #"The message of an alert.")
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction
actionWithTitle:NSLocalizedString(#"OK", #"A common affirmative action title, like 'OK' in english.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
}];
UIAlertAction *dontshowagain = [UIAlertAction
actionWithTitle:NSLocalizedString(#"Don't Show Again", #"A common decline action title, like 'NO' in english.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[[NSUserDefaults standardUserDefaults] setValue:#"1" forKey:#"alert"];
[[NSUserDefaults standardUserDefaults] synchronize];
}];
[alert addAction:ok];
[alert addAction:dontshowagain];
[self presentViewController:alert animated:YES completion:nil];
Let me know if this helps!

Resources