Presenting a view from a UIAlertController
moves the alert to a buggy position at the top-left corner of the screen. iOS 8.1, device and simulator.
We h
In addition to Carl Lindberg's answer There are two cases that also should be taken into account:
So, the full answer that worked for me:
// fix for rotation
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id context) {
} completion:^(id context) {
[self.view setNeedsLayout];
}];
}
// fix for keyboard
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
NSDictionary *keyboardUserInfo = [notification userInfo];
CGSize keyboardSize = [[keyboardUserInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
self.keyboardHeight = keyboardSize.height;
[self.view setNeedsLayout];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
self.keyboardHeight = 0;
[self.view setNeedsLayout];
}
// position layout fix
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self fixAlertPosition];
}
-(void)fixAlertPosition
{
if (self.preferredStyle == UIAlertControllerStyleAlert && self.view.window)
{
CGRect myRect = self.view.bounds;
CGRect windowRect = [self.view convertRect:myRect toView:nil];
if (!CGRectContainsRect(self.view.window.bounds, windowRect) || CGPointEqualToPoint(windowRect.origin, CGPointZero))
{
CGRect myFrame = self.view.frame;
CGRect superBounds = self.view.superview.bounds;
myFrame.origin.x = CGRectGetMidX(superBounds) - myFrame.size.width / 2;
myFrame.origin.y = (superBounds.size.height - myFrame.size.height - self.keyboardHeight) / 2;
self.view.frame = myFrame;
}
}
else if (self.preferredStyle == UIAlertControllerStyleActionSheet && self.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPhone && self.view.window)
{
CGRect myRect = self.view.bounds;
CGRect windowRect = [self.view convertRect:myRect toView:nil];
if (!CGRectContainsRect(self.view.window.bounds, windowRect) || CGPointEqualToPoint(windowRect.origin, CGPointZero))
{
UIScreen *screen = self.view.window.screen;
CGFloat borderPadding = ((screen.nativeBounds.size.width / screen.nativeScale) - myRect.size.width) / 2.0f;
CGRect myFrame = self.view.frame;
CGRect superBounds = self.view.superview.bounds;
myFrame.origin.x = CGRectGetMidX(superBounds) - myFrame.size.width / 2;
myFrame.origin.y = superBounds.size.height - myFrame.size.height - borderPadding;
self.view.frame = myFrame;
}
}
}
Also, if using category, then you need to store keyboard height somehow, like this:
@interface UIAlertController (Extended)
@property (nonatomic) CGFloat keyboardHeight;
@end
@implementation UIAlertController (Extended)
static char keyKeyboardHeight;
- (void) setKeyboardHeight:(CGFloat)height {
objc_setAssociatedObject (self,&keyKeyboardHeight,@(height),OBJC_ASSOCIATION_RETAIN);
}
-(CGFloat)keyboardHeight {
NSNumber *value = (id)objc_getAssociatedObject(self, &keyKeyboardHeight);
return value.floatValue;
}
@end