uncaught exception 'NSGenericException: application has presented a UIAlertController of style UIAlertControllerStyleActionSheet - ios

I am working on an app which i run on iPhone works well but when i am trying to run on iPad it crashes
Here is my code:
- (void)parseCountryStates:(NSDictionary *)json
{
countryPickerView.hidden = TRUE;
NSDictionary *listing = [json objectForKey:#"country"];
countryArray = [listing allValues];
countryIDArray = [listing allKeys];
[countryPickerView reloadAllComponents];
alertController = [UIAlertController
alertControllerWithTitle:#"Select Service Type"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
int count = (int)[countryPickerView numberOfRowsInComponent:0];
for (int i = 0; i < count; i++)
{
UIAlertAction* button = [UIAlertAction
actionWithTitle:[[countryPickerView delegate] pickerView:countryPickerView titleForRow:i forComponent:0]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
countryField.text = [action title];
countryStr = countryField.text;
if ([countryArray containsObject:countryStr]) {
countryidStr = [countryIDArray objectAtIndex:[countryArray indexOfObject:countryStr]];
NSLog(#"CountryidStr %#",countryidStr);
[self getState];
}
}];
[alertController addAction:button];
}
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action)
{
// UIAlertController will automatically dismiss the view
}];
[alertController addAction:cancel];
[self presentViewController:alertController animated:true completion:nil];
}
I am sharing the crash log of it
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController () of
style UIAlertControllerStyleActionSheet. The modalPresentationStyle of
a UIAlertController with this style is UIModalPresentationPopover. You
must provide location information for this popover through the alert
controller's popoverPresentationController. You must provide either a
sourceView and sourceRect or a barButtonItem. If this information is
not known when you present the alert controller, you may provide it in
the UIPopoverPresentationControllerDelegate method
-prepareForPopoverPresentation.

Add source view and source rect to your alertController.
[[alertController popoverPresentationController] setSourceView:self.view];
[[alertController popoverPresentationController] setSourceRect:CGRectMake(0,0,1,1)];
[[alertController popoverPresentationController] setPermittedArrowDirections:UIPopoverArrowDirectionUp];
[self presentViewController:alertController animated:true completion:nil];

actully on ipad alertcontrollers are not allowed instead you can use pop overs to diaplay kind of alert
Programtically
UIViewController *newViewCont = [[UIViewController alloc] init];
newViewCont.view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 180, 180)];
newViewCont.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:newViewCont animated:YES completion:nil];
UIPopoverPresentationController *pop = [newViewCont popoverPresentationController];
pop.permittedArrowDirections = UIPopoverArrowDirectionAny;
[pop setSourceView:myButton];
[pop setSourceRect:myButton.bounds];
Using storyboards
// grab the view controller we want to show
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:#"Pop"];
// present the controller
// on iPad, this will be a Popover
// on iPhone, this will be an action sheet
controller.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:controller animated:YES completion:nil];
// configure the Popover presentation controller
UIPopoverPresentationController *popController = [controller popoverPresentationController];
popController.permittedArrowDirections = UIPopoverArrowDirectionUp;
popController.delegate = self;
// in case we don't have a bar button as reference
popController.sourceView = self.view;
popController.sourceRect = CGRectMake(30, 50, 10, 10);
dismiss popover
[self dismissViewControllerAnimated:YES completion:nil];
There’s a new protocol called the UIPopoverPresentationControllerDelegate that is called upon dismissal and position change due to rotation or interface changes. We can even prevent a Popover from being dismissed if we wish. Here are the three methods we can implement:
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// called when a Popover is dismissed
}
- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// return YES if the Popover should be dismissed
// return NO if the Popover should not be dismissed
return YES;
}
- (void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing _Nonnull *)view {
// called when the Popover changes position
}
Don’t forget to conform to the protocol, and set the delegate to your reacting class.

UIPopovers are not allowed on iPads, but there is a way you can do this as other answers have indicated. Here is a Swift 5.x version.
let ac = UIAlertController(title: "Some title goes here", message: nil, preferredStyle: .actionSheet)
ac.addAction(UIAlertAction(title: "Some button name", style: .default) {
[unowned self] _ in
// stuff to do goes here
self.doSomething()
})
// iPad specific code
ac.popoverPresentationController?.sourceView = self.view
let xOrigin = nil // Replace this with one of the lines at the end
let popoverRect = CGRect(x: xOrigin, y: 0, width: 1, height: 1)
ac.popoverPresentationController?.sourceRect = popoverRect
ac.popoverPresentationController?.permittedArrowDirections = .up
present(ac, animated: true)
Replacing the the let xOrigin = nil line with one of the ones below will control where the popover appears below the navigation bar. You can also change x and y to the proper value in the bounds or frame of a different element if you have control that is below the nav bar on an iPad.
Top Left
let xOrigin = 0
Top Middle
let xOrigin = self.view.bounds.width / 2
Top Right
let xOrigin = self.view.bounds.width
Hope this helps.

Related

iOS popover show twice will crash

I'm using objective-c write about UIAlertControllerStyleActionSheet of UIAlertcontroller.
I want to show alert sheet on the iPhone, and popoverPresentationController on the iPad.
First, I have set the UIPopoverPresentationControllerDelegate delegate.
When I click my button, the pop over have show is correct.
But I click on the screen dismiss the popover. it will show below warning.
[Warning] <_UIPopoverBackgroundVisualEffectView 0x14be52ef0> is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
Now When I click the button show the pop view again.
It will crash show below log.
Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController () of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'
*** First throw call stack:
(0x18d9a41c0 0x18c3dc55c 0x19418a8b0 0x193ac60a8 0x193ac3df4 0x193a08d0c 0x1939faac0 0x19376a22c 0x18d9517dc 0x18d94f40c 0x18d94f89c 0x18d87e048 0x18f2ff198 0x1937e2b50 0x1937dd888 0x10011198c 0x18c8605b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
Have anyone know how to resolve the problem?
My code is below:
#interface ViewController () <...UITextViewDelegate,UITextFieldDelegate...> {
UIAlertController *alertTypeAlertController;
UIAlertAction *alertType1Action;
UIAlertAction *alertType2Action;
UIPopoverPresentationController *popPresenter;
}
- (void)viewDidLoad {
[super viewDidLoad];
alertTypeAlertController = [UIAlertController
alertControllerWithTitle:#"selecte one:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alertType1Action = [UIAlertAction
actionWithTitle:#"Type1"
style:UIAlertActionStyleDefault
handler:nil];
alertType2Action = [UIAlertAction
actionWithTitle:#"Type2"
style:UIAlertActionStyleDefault
handler:nil];
[alertTypeAlertController addAction: alertType1Action];
[alertTypeAlertController addAction: alertType2Action];
// for ipad
popPresenter = [alertTypeAlertController popoverPresentationController];
popPresenter.permittedArrowDirections = UIPopoverArrowDirectionLeft;
popPresenter.delegate = self;
popPresenter.sourceView = self.theTypeBtn;
popPresenter.sourceRect = CGRectMake(230, 22, 10, 10);
....
}
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// called when a Popover is dismissed
}
- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
// return YES if the Popover should be dismissed
// return NO if the Popover should not be dismissed
return YES;
}
-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
enter code here
Thank you very much.
Maybe the UIAlertController and UIPopoverPresentationController objects strongly referenced by the ViewController object which makes
the Popover can't release after you dismiss it.
I later found your problem is that you try to create popPresenter
once in the viewDidLoad method and present it every time you touch
the button,you should create a new one instead,you can move the ViewDidLoad code to a new method,and call it by touch event, fix like this:
- (void)makePopover
{
alertTypeAlertController = [UIAlertController
alertControllerWithTitle:#"selecte one:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alertType1Action = [UIAlertAction
actionWithTitle:#"Type1"
style:UIAlertActionStyleDefault
handler:nil];
alertType2Action = [UIAlertAction
actionWithTitle:#"Type2"
style:UIAlertActionStyleDefault
handler:nil];
[alertTypeAlertController addAction: alertType1Action];
[alertTypeAlertController addAction: alertType2Action];
// for ipad
popPresenter = [alertTypeAlertController popoverPresentationController];
popPresenter.permittedArrowDirections = UIPopoverArrowDirectionLeft;
popPresenter.canOverlapSourceViewRect = YES; // adding this line
popPresenter.delegate = self;
popPresenter.sourceView = self.theTypeBtn;
popPresenter.sourceRect = CGRectMake(230, 22, 10, 10);
}
- (IBAction)touchButton:(id)sender {
[self makePopover];
[self presentViewController:alertTypeAlertController animated:YES completion:nil];
}
I am just modifying your code, please check if it is working or not.
- (IBAction)actionButton:(UIButton*)sender {
alertTypeAlertController = [UIAlertController
alertControllerWithTitle:#"selecte one:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alertType1Action = [UIAlertAction
actionWithTitle:#"Type1"
style:UIAlertActionStyleDefault
handler:nil];
alertType2Action = [UIAlertAction
actionWithTitle:#"Type2"
style:UIAlertActionStyleDefault
handler:nil];
[alertTypeAlertController addAction: alertType1Action];
[alertTypeAlertController addAction: alertType2Action];
// for ipad
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
popPresenter = [alertTypeAlertController popoverPresentationController];
popPresenter.permittedArrowDirections = UIPopoverArrowDirectionLeft;
popPresenter.delegate = self;
popPresenter.sourceView = self.theTypeBtn;
popPresenter.sourceRect = CGRectMake(230, 22, 10, 10);
}
[self presentViewController:alertTypeAlertController animated:YES completion:nil];
}

UIPopoverPresentationController being cut on iPad iOS 10

Im trying to show a list inside a popover controller using
UIAlertController. Works well on iOS 8, 9. On iOS 10 ipad it gets cut. Although I am adding actions and verified it is being added but the popover gets cut. Please suggest . Below is my code -
UIAlertController * view= [UIAlertController
alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
if(IS_IPAD) {
UIPopoverPresentationController *popPresenter = [view
popoverPresentationController];
[view setModalPresentationStyle:UIModalPresentationPopover];
[view setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
popPresenter.sourceView = self.view;
popPresenter.sourceRect = CGRectMake(70, 0, self.view.frame.size.width, self.view.frame.size.height);
popPresenter.barButtonItem = self.navigationItem.leftBarButtonItem;
}
// Add Cacel Action
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(#"إلغاء", #"'Cancel' title for button")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
[view dismissViewControllerAnimated:YES completion:nil];
}];
[view addAction:cancelAction];
[self.liveFeed.filter.filtersItems enumerateObjectsUsingBlock:^(DPFilteritem *item, NSUInteger idx, BOOL * _Nonnull stop) {
if (![item.filterName isKindOfClass:[NSNull class]] && item.filterName.length > 0) {
UIAlertAction* alertAction = [UIAlertAction
actionWithTitle:item.filterName
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
//Do some thing here
NSUInteger index = [[view actions]indexOfObject:action];
[view dismissViewControllerAnimated:YES completion:nil];
[self didSelectAlertItemAtIndex:index];
}];
[view addAction:alertAction];
}
}];
view.view.tintColor = [UIColor blackColor];
dispatch_async(dispatch_get_main_queue(), ^ {
[self presentViewController:view animated:YES completion:^{
//fix for iOS 9 - known issue in iOS9. You need to set tint color in completion handler.
view.view.tintColor = [UIColor blackColor];
}];
});
iOS 10 - ipad -
iOS 9 - ipad -

UIAlertController background color iOS10

Code that I wrote for iOS9, worked really well:
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Select source"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alert.view.backgroundColor = DARK_BLUE;
alert.view.tintColor = NEON_GREEN;
UIView *subview = alert.view.subviews.firstObject;
UIView *alertContentView = subview.subviews.firstObject;
alertContentView.backgroundColor = DARK_BLUE;
alertContentView.layer.cornerRadius = 10;
My point of view is that UIAlertController is inheriting from UIViewController, and UIViewController have property UIView that can be changed. And this is working. Now, that view inherited from UIViewController have it's own subview that is contentView showed as Alert. I can access it as firstObject in array of subviews. Now, why message for sending background color isn't working anymore? Do anyone know some new solution?
For everyone that will bump into the same problem, I've found the solution:
UIAlertController.view contains one subview, that is only container.
That subview contains subview that contains two it's own subviews, one is container, and another is layer for blurring it.
So, it needs for in loop to iterate through that two subviews and change background color of both.
Full code:
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Select source"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
alert.view.tintColor = NEON_GREEN;
UIView *firstSubview = alert.view.subviews.firstObject;
UIView *alertContentView = firstSubview.subviews.firstObject;
for (UIView *subSubView in alertContentView.subviews) { //This is main catch
subSubView.backgroundColor = DARK_BLUE; //Here you change background
}
In Swift 3.0
let FirstSubview = alertController.view.subviews.first
let AlertContentView = FirstSubview?.subviews.first
for subview in (AlertContentView?.subviews)! {
subview.backgroundColor = UIColor.black
subview.layer.cornerRadius = 10
subview.alpha = 1
subview.layer.borderWidth = 1
subview.layer.borderColor = UIColor.yellow.cgColor
}
I use this:
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Alert!"
message:#"Message of alert"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Your code
}];
[alert addAction:defaultAction];
UIView * topview = alert.view.subviews.firstObject;
UIView * colorView = topview.subviews.firstObject;
colorView.backgroundColor = [UIColor yellowColor];
colorView.layer.cornerRadius = 10;
[self presentViewController:alert animated:YES completion:nil];

previewActionItems not getting called (Force touch action)

I am using below code to add force touch preview actions... Peek and pop view works great, only actions are not showing... Please help my code is not getting executed for some reason, take a look:
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
if (_previewActions == nil) {
UIPreviewAction *rateAction = [UIPreviewAction actionWithTitle:#"Rate" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
EmbededRateViewController *embededRVC = [[EmbededRateViewController alloc]initWithEmployerToRate:self.employersArray[0]];
embededRVC.view.bounds = CGRectMake(0, 0, self.view.frame.size.width - 40, 210);
[embededRVC setPopinTransitionStyle:BKTPopinTransitionStyleSnap];
BKTBlurParameters *blurParameters = [[BKTBlurParameters alloc] init];
blurParameters.tintColor = [UIColor colorWithWhite:0 alpha:0.5];
blurParameters.radius = 0.3f; // 0.3
[embededRVC setBlurParameters:blurParameters];
[embededRVC setPopinTransitionDirection:BKTPopinTransitionDirectionTop];
[self.collectionView setScrollEnabled:NO];
[self presentPopinController:embededRVC animated:YES completion:^{
NSLog(#"Popin presented !");
}];
}];
UIPreviewAction *commentAction = [UIPreviewAction actionWithTitle:#"Comment" style:UIPreviewActionStyleDefault handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
NewCommentViewController *ncvc = [[NewCommentViewController alloc]initWithEmployer:self.employersArray[0]];
[self presentViewController:ncvc animated:YES completion:nil];
}];
UIPreviewAction *reportAction = [UIPreviewAction actionWithTitle:#"Report" style:UIPreviewActionStyleDestructive handler:^(UIPreviewAction * _Nonnull action, UIViewController * _Nonnull previewViewController) {
ReportEmployerViewController *reportEmpVC = [[ReportEmployerViewController alloc]initWithEmployer:self.employersArray[0]];
[self presentViewController:reportEmpVC animated:YES completion:nil];
}];
UIPreviewAction *cancelAction =
[UIPreviewAction actionWithTitle:#"Cancel"
style:UIPreviewActionStyleSelected
handler:^(UIPreviewAction *action,
UIViewController *previewViewController){
}];
_previewActions = #[commentAction, rateAction, reportAction, cancelAction];
}
return _previewActions;
}
I was facing the same issue was was stuck for long.
The mistake that i did was adding this method in the Caller View Controller.
DO NOT add this method in the caller view controller , add it in the called view controller instead.
For example if you are presenting View Controller B (called) on force touch of View Controller A(caller), then add this method to the View Controller B (called).
and was too obvious , because we are handling the button actions in View controller B.
Hope it helps you.
All the best.

How to dismiss an UIAlertController and the keyboard simultaneously?

I have created a signup form with a UIAlertController and used the method addTextFieldWithConfigurationHandler to add a text field. But there is a little problem.
When the form shows up, the keyboard and modal appear with a smooth animation. When closing the form, the modal disappears first, and then the keyboard disappears. This makes the keyboard make a sudden downward fall.
How can I make the modal and keyboard graciously disappear?
lazy var alertController: UIAlertController = { [weak self] in
let alert = UIAlertController(title: "Alert", message: "This is a demo alert", preferredStyle: .Alert)
alert.addTextFieldWithConfigurationHandler { textField in
textField.delegate = self
}
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
return alert
}()
#IBAction func alert() {
presentViewController(alertController, animated: true, completion: nil)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
alertController.dismissViewControllerAnimated(true, completion: nil)
return true
}
You can set your view controller or other object as transitioning delegate of your UIAlertController (alert.transitioningDelegate) and make a custom animation for dismissing.
Code sample:
#interface ViewController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning, UITextFieldDelegate>
#property (assign, nonatomic) NSTimeInterval keyboardAnimationDuration;
#property (assign, nonatomic) CGFloat keyboardHeight;
#property (nonatomic, strong) UIAlertController *alertController;
#property (nonatomic,strong) id <UIViewControllerTransitioningDelegate> transitioningDelegateForAlertController;
#end
#implementation ViewController
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self subscribeForKeyboardNotification];
}
#pragma mark - Keyboard notifications
- (void)subscribeForKeyboardNotification {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillAppear:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (void)keyboardWillAppear:(NSNotification *)notification {
self.keyboardAnimationDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.keyboardHeight = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
}
#pragma mark - IBAction
- (IBAction)showAlertButtonPressed:(id)sender {
[self showAlert];
}
- (void)showAlert {
self.alertController = [UIAlertController alertControllerWithTitle:#"Alert"
message:#"This is a demo alert"
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.delegate = weakSelf;
}];
self.transitioningDelegateForAlertController = self.alertController.transitioningDelegate;
self.alertController.transitioningDelegate = self;
[self.alertController addAction:[UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:self.alertController animated:YES completion:nil];
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.alertController dismissViewControllerAnimated:YES completion:nil];
return YES;
}
#pragma mark - UIViewControllerTransitioningDelegate
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source {
return [self.transitioningDelegateForAlertController animationControllerForPresentedController:presented
presentingController:presenting
sourceController:source];
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
return self;
}
#pragma mark - UIViewControllerAnimatedTransitioning
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return self.keyboardAnimationDuration ?: 0.5;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
UIViewController *destination = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if ([destination isBeingPresented])
[self animatePresentation:transitionContext];
else
[self animateDismissal:transitionContext];
}
- (void)animatePresentation:(id <UIViewControllerContextTransitioning>)transitionContext {
NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
UIViewController *fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *container = transitionContext.containerView;
fromController.view.frame = container.bounds;
toController.view.frame = container.bounds;
toController.view.alpha = 0.0f;
[container addSubview:toController.view];
[fromController beginAppearanceTransition:NO animated:YES];
[UIView animateWithDuration:transitionDuration
animations:^{
toController.view.alpha = 1.0;
}
completion:^(BOOL finished) {
[fromController endAppearanceTransition];
[transitionContext completeTransition:YES];
}];
}
- (void)animateDismissal:(id <UIViewControllerContextTransitioning>)transitionContext {
NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
UIViewController *fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
[toController beginAppearanceTransition:YES animated:YES];
[UIView animateWithDuration:transitionDuration
animations:^{
fromController.view.alpha = 0.0;
[fromController.view endEditing:YES];
CGRect frame = fromController.view.frame;
frame.origin.y += self.keyboardHeight / 2;
fromController.view.frame = frame;
}
completion:^(BOOL finished) {
[toController endAppearanceTransition];
[transitionContext completeTransition:YES];
}];
}
#end
Result:
P.S.: I used old alert's transitioning delegate for presentation because I can't reproduce an original animation. So animatePresentation: method is never used.
I had the exact same problem you had and found the solution incidentally. You probably don't need this anymore, but for the sake of others like me, here is the answer:
Swift:
override func canBecomeFirstResponder() -> Bool {
return true
}
Objective-C:
- (BOOL)canBecomeFirstResponder {
return true;
}
Just add this code in the view controller handling the alert. Only tested in swift.
Its pretty simple.
if your UIAlertController delegate are present in self View Controller. then you can do it in its delegate method for Dismiss AlertController. You can [youtTextField resignFirstResponder] in your UIAlertController object which have a button for dismiss it. (like OK or Cancel) so your presented KeyBoard will be dismissed.
I didn't tried it but It will work. but you have to handle textField and Alert correctly.
I assume the jumping down of the UIAlertController is if it dismisses after you press 'return' on the keyboard. If so, I have found a way for the Alert and keyboard to dismiss smoothly from a return action.
You will need declare the UIAlertController within the class file
#property (strong, nonatomic) UIAlertController *alertController;
And you will also need to use the UITextFieldDelegate with the viewController
When adding the textField to the UIAlertController this is where you will need to set the delegate of it to self. (weakSelf used as it is within a block)
#interface ViewController ()<UITextFieldDelegate>
Within the method you are auctioning the UIAlertController -
self.alertController = [UIAlertController alertControllerWithTitle:#"Alert" message:#"This is the message" preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.delegate = weakSelf;
}];
[self presentViewController:self.alertController animated:YES completion:nil];
Add this UITextField delegate method which will fire once the return button has been pressed on the keyboard. This means you can action for the UIAlertController to dismiss just prior to the keyboard dismissing, thus it makes it all work smoothly.
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[self.alertController dismissViewControllerAnimated:YES completion:nil];
return YES;
}
I've tested this and should work exactly the way you require.
Thanks,
Jim
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self.view endEditing:YES];
// or you can write [yourtextfield refignFirstResponder]
[alertView dismissWithClickedButtonIndex:buttonIndex animated:TRUE];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex==1) {
[[alertView textFieldAtIndex:0] resignFirstResponder];
} else {
[[alertView textFieldAtIndex:0] resignFirstResponder];
}
}
Use your button index (Ok or Cancel button index)
no need to do any thing you just have to implement this much of code, it works for me, no need to declare any kind of delegate methods
- (void)showAlert {
self.alertController = [UIAlertController alertControllerWithTitle:#"Alert"
message:#"Enter Name:"
preferredStyle:UIAlertControllerStyleAlert];
[self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
}];
[self.alertController addAction:[UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:self.alertController animated:YES completion:nil];
}
Swizzle viewWillDisappear method for UIAlertController, and perform resignFirstResponder on correspodent text field or call endEditing: on controller's view
I am using for this ReactiveCocoa:
let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert)
alert.addTextFieldWithConfigurationHandler {
textField in
}
let textField = alert.textFields!.first!
alert.rac_signalForSelector(#selector(viewWillDisappear(_:)))
.subscribeNext {
_ in
textField.resignFirstResponder()
}

Resources