UIKeyboard避免和自动布局

鉴于iOS 6中的自动布局,以及苹果工程师的build议( 请参阅WWDC 2012video )的build议,我们不再直接操纵视图的框架,如何避免键盘只使用自动布局和NSLayoutConstraint?

更新

这看起来像一个合理的解决scheme: 一个键盘敏感的布局 ( GitHub源) 的例子,但我看到一个潜在的问题是当用户旋转设备和键盘已经在屏幕上会发生什么?

我的想法是创build一个UIView ,让我们称之为键盘视图 ,并将其放置到您的视图控制器的视图。 然后观察键盘框更改通知UIKeyboardDidChangeFrameNotification ,并将键盘的框架与键盘视图相匹配(我build议为更改设置animation效果)。 观察这个通知可以处理你提到的旋转,也可以在iPad上移动键盘。

然后简单地创build相对于这个键盘视图的约束。 不要忘记将约束添加到他们的共同超视图。

要正确地翻译键盘框架并旋转到您的视图坐标,请查看UIKeyboardFrameEndUserInfoKey的文档。

那篇博文很棒,但是我想提出一些改进build议。 首先,您可以注册观察框架更改,因此您不需要注册观察显示和隐藏通知。 其次,你应该把CGRects的键盘从屏幕转换到查看坐标。 最后,您可以将iOS使用的确切animation曲线复制到键盘本身,使键盘和跟踪视图同步移动。

把它放在一起,你会得到以下结果:

 @interface MyViewController () // This IBOutlet holds a reference to the bottom vertical spacer // constraint that positions the "tracking view",ie, the view that // we want to track the vertical motion of the keyboard @property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomVerticalSpacerConstraint; @end @implementation MyViewController -(void)viewDidLoad { [super viewDidLoad]; // register for notifications about the keyboard changing frame [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:self.view.window]; } -(void)keyboardWillChangeFrame:(NSNotification*)notification { NSDictionary * userInfo = notification.userInfo; UIViewAnimationCurve animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue]; NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; // convert the keyboard's CGRect from screen coords to view coords CGRect kbEndFrame = [self.view convertRect:[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:self.view.window]; CGRect kbBeginFrame = [self.view convertRect:[[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view.window]; CGFloat deltaKeyBoardOrigin = kbEndFrame.origin.y - kbBeginFrame.origin.y; // update the constant factor of the constraint governing your tracking view self.bottomVerticalSpacerConstraint.constant -= deltaKeyBoardOrigin; // tell the constraint solver it needs to re-solve other constraints. [self.view setNeedsUpdateConstraints]; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:duration]; [UIView setAnimationCurve:animationCurve]; [UIView setAnimationBeginsFromCurrentState:YES]; // within this animation block, force the layout engine to apply // the new layout changes immediately, so that we // animate to that new layout. We need to use old-style // UIView animations to pass the curve type. [self.view layoutIfNeeded]; [UIView commitAnimations]; } -(void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil]; } @end 

只要在键盘启动时不改变方向,这将起作用。

这是一个关于如何在iOS 7上模拟键盘animation以将“完成”button添加到数字键盘的答案? 展示了如何正确模仿键盘animation曲线。

关于所有这些基于通知的解决scheme,最后要注意的是:如果应用程序中的某个屏幕也使用键盘,它们可能会产生意想不到的效果,因为只要视图控制器还没有被释放,视图控制器仍然会收到通知,即使它的意见被卸载。 对此的一个补救措施是在通知处理程序中添加一个条件,以确保只有在视图控制器在屏幕上时才能运行。

我创build了一个这样的视图,当键盘开启/closures屏幕时,它将观察键盘并更改自己的约束。

 @interface YMKeyboardLayoutHelperView () @property (nonatomic) CGFloat desiredHeight; @property (nonatomic) CGFloat duration; @end @implementation YMKeyboardLayoutHelperView - (id)init { self = [super init]; if (self) { self.translatesAutoresizingMaskIntoConstraints = NO; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:@"UIKeyboardWillShowNotification" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:@"UIKeyboardWillHideNotification" object:nil]; } return self; } - (void)keyboardWillShow:(NSNotification *)notification { // Save the height of keyboard and animation duration NSDictionary *userInfo = [notification userInfo]; CGRect keyboardRect = [userInfo[@"UIKeyboardBoundsUserInfoKey"] CGRectValue]; self.desiredHeight = CGRectGetHeight(keyboardRect); self.duration = [userInfo[@"UIKeyboardAnimationDurationUserInfoKey"] floatValue]; [self setNeedsUpdateConstraints]; } - (void)keyboardWillHide:(NSNotification *)notification { // Reset the desired height (keep the duration) self.desiredHeight = 0.0f; [self setNeedsUpdateConstraints]; } - (void)updateConstraints { [super updateConstraints]; // Remove old constraints if ([self.constraints count]) { [self removeConstraints:self.constraints]; } // Add new constraint with desired height NSString *constraintFormat = [NSString stringWithFormat:@"V:[self(%f)]", self.desiredHeight]; [self addVisualConstraints:constraintFormat views:@{@"self": self}]; // Animate transition [UIView animateWithDuration:self.duration animations:^{ [self.superview layoutIfNeeded]; }]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } @end 

在Spring框架中使用KeyboardLayoutConstraint是迄今为止我find的最简单的解决scheme。 KeyboardLayoutConstraint

我写了一个库,将为你做的一切(支持自动布局和弹簧与Struts)

IHKeyboardAvoiding https://github.com/IdleHandsApps/IHKeyboardAvoiding

只要调用[IHKeyboardAvoiding setAvoidingView:self.myView];

对于键盘shell的自动布局,我使用静态表格视图。 这使您的代码更简单,不需要跟踪键盘高度。 我了解的一个关于表格视图的事情是让每个表格行尽可能的窄。 如果在一行中垂直放置太多UI,则可能会出现键盘重叠。