objective-c - UIKeyboard回避和自动布局

  显示原文与译文双语对照的内容

考虑到在 iOS 6中的自动布局,以及苹果工程师( 看到wwdc 2012视频) 建议我们不要长时间操作视图'框架,如何避免使用自动布局和NSLayoutConstraint的键盘?

更新

这是一个合理的解决方案: 一个键盘敏感布局的例子 ( GitHub源) 但是我看到的一个潜在问题是当用户旋转设备并且键盘已经在屏幕上时

时间:

我的想法是创建一个 UIView,让我们称之为键盘视图,并将它放到控制器视图视图。 然后观察键盘帧更改通知 UIKeyboardDidChangeFrameNotification 并将键盘的帧与键盘视图 ( 我建议对更改进行动画处理) 匹配。 观察这里通知处理你提到的旋转并在iPad上移动键盘。

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

要使键盘框架正确转换并旋转到你的视图坐标,请查看 UIKeyboardFrameEndUserInfoKey 文档。

博客帖子很棒,但我想对它提出一些改进。 首先,你可以注册观察框架的变化,因此你不需要注册来观察显示和隐藏通知。 第二,你应该将键盘的CGRects转换为视图坐标。 最后,你可以复制iOS用于键盘本身的动画曲线,这样键盘和跟踪视图就会同步移动。

将它们放在一起,你可以得到以下内容:


@interface MyViewController ()
//This IBOutlet holds a reference to the bottom vertical spacer
//constraint that positions the"tracking view",i.e., 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

只要你在键盘上不改变方向,这就可以了。

7上如何模拟键盘动画以将"已经完成"按钮添加到数字键盘上的回答? 显示了如何正确模拟键盘动画曲线。

对于所有这些notification-based解决方案,需要注意的最后一点: 如果应用程序中的其他屏幕也使用键盘,因为你的view controller仍将接收到通知,即使它是视图被卸载,也会产生意外效果。 一个解决方法是在通知处理程序中放置一个条件,以确保在 view controller处于打开状态时只运行。

我创建了这样一个视图,它可以在键盘打开/关闭屏幕时观察键盘并改变它自己的约束。


@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

中使用 KeyboardLayoutConstraintspring 框架是最简单的解决方案到目前为止我已经发现了。 KeyboardLayoutConstraint

我已经编写了一个库来为你做所有的事情( 支持自动布局和 spring & Struts )

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

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

对于使用键盘大小写的自动布局,我使用静态表格视图。 这使得代码更加简单,不需要跟踪键盘高度。 关于表格视图,我学到的一件事是让每个表格行尽可能窄。 如果在一行中垂直放置过多的用户界面,可能会导致键盘重叠。

...