Objective c UIC键盘避免和自动布局
考虑到iOS 6中对自动布局的关注,以及苹果工程师的建议(见WWDC 2012视频),即我们不再直接操作视图的框架,如何避免仅使用自动布局和NSLAYOUTSCONSTRAINT来使用键盘 更新Objective c UIC键盘避免和自动布局,objective-c,ios,cocoa-touch,uiviewcontroller,ios6,Objective C,Ios,Cocoa Touch,Uiviewcontroller,Ios6,考虑到iOS 6中对自动布局的关注,以及苹果工程师的建议(见WWDC 2012视频),即我们不再直接操作视图的框架,如何避免仅使用自动布局和NSLAYOUTSCONSTRAINT来使用键盘 更新 这看起来是一个合理的解决方案:(但我看到的一个潜在问题是,当用户旋转设备并且键盘已经在屏幕上时会发生什么?对于键盘外壳的自动布局,我使用静态表格视图。这使代码更简单,不需要跟踪键盘高度。关于表格视图,我学到的一件事是使每个表格行尽可能窄。)le.如果在一行中垂直放置太多UI,可能会出现键盘重叠。我的想法
这看起来是一个合理的解决方案:(但我看到的一个潜在问题是,当用户旋转设备并且键盘已经在屏幕上时会发生什么?对于键盘外壳的自动布局,我使用静态表格视图。这使代码更简单,不需要跟踪键盘高度。关于表格视图,我学到的一件事是使每个表格行尽可能窄。)le.如果在一行中垂直放置太多UI,可能会出现键盘重叠。我的想法是创建一个
UIView
,我们称之为键盘视图,并将其放置到视图控制器的视图中。然后观察键盘帧更改通知UIKeyboardDidChangeFrameNotification
,并将键盘帧与ke匹配yboard视图(我建议设置更改的动画)。观察此通知可以处理您提到的旋转,还可以在iPad上移动键盘
然后简单地创建与此键盘视图相关的约束。不要忘记将约束添加到它们的公共superview
要将键盘框架正确地转换和旋转到视图坐标,请查看
UIKeyboardFrameEndUserInfoKey
的文档。我创建了这样一个视图,当键盘打开/关闭屏幕时,它可以观察键盘并更改自身的约束
@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
这篇博文很棒,但我想对它提出一些改进建议。首先,你可以注册来观察帧的变化,所以你不需要注册来观察显示和隐藏通知。其次,你应该将键盘的CGRECT从屏幕坐标转换为视图坐标。最后,你可以复制iOS f使用的精确动画曲线或者键盘本身,因此键盘和跟踪视图同步移动 综上所述,您可以得到以下结果:
@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
只要你在键盘打开时不改变方向,这就行了
这是一个关于如何正确模拟键盘动画曲线的答案
对于所有这些基于通知的解决方案,最后要注意的一点是:如果应用程序中的其他屏幕也使用了键盘,它们可能会产生意外的效果,因为只要视图控制器尚未解除分配,即使其视图已卸载,视图控制器仍将接收通知。解决此问题的一个方法是通知处理程序中的一个条件,以确保它仅在视图控制器在屏幕上时运行。我编写了一个库,可以为您完成所有操作(支持自动布局和Springs&Struts) 键盘回避 只需调用[IHKeyboardAvoidingView:self.myView];在框架中使用是迄今为止我找到的最简单的解决方案。
以链接中的示例为例,我将重构代码以计算
键盘高度
,并添加willRotateToInterfaceOrientation:
和/或WillAnimateRotationInterfaceOrientation:
根据需要调用以更新键盘高度约束。UIKeyboard将显示通知
notif当键盘的大小因旋转而改变时,也会发布通知,因此您不必担心。+1对于有趣的链接,以这种方式使用代理视图效果非常好;好主意!我已经实现了这样一个视图,请免费使用:3我编写了一个库,可以为您完成所有操作(支持自动布局和Springs&Struts)这是一个使用自动布局处理编辑表单的优雅解决方案。许多通知应该在ViewWillDisplay中注册,而在ViewWillEnglishe中取消注册。@StevenCramer我的印象是(1)ViewWillDisplay和ViewWillEnglish不是可靠的平衡调用,以及(2)在许多情况下,当视图可见时(应用程序恢复活动等),视图将特别显示。因此,我不确定如何最好地使用它们来管理通知。你有什么具体的想法吗?过去经常发生这种情况,但现在(iOS 5+)并没有这样的问题。事实上,如果您仍然有不平衡的外观消息,我建议您立即修复。或者解决它,如果它是一个框架问题。哦,wrt到“应用程序恢复活动”。事实上,不获取viewWill(Dis)显示消息是正确的。“外观”提到的是视图在应用程序窗口中的外观,而不是在设备屏幕上。对于我来说,我使用的是iOS 8,消息出现两次。一次是框架进入我的视图,另一次是通知我它进入视图外的位置。因此-=正在将其丢弃。我必须添加一个位置检查,以查看它是否正确远距视图/屏幕的大小[code]!(kbbeginrame.origin.y>self.window.frame.size.height | | kbEndFrame.origin.y>self.window.frame.size.height);[code]+1,不是因为这是所有情况下的最佳解决方案,而是如果您的项目已经在使用Spring框架,那么这就是最好的解决方案。无需使用该框架,只需将KeyboardLayoutConstraint.swift文件复制到您的项目中,并随意使用它。提醒使用此策略的人,KeyboardLayoutConstraint不能处理bluetooth keyb正确发送通知。请参阅此处了解解决方案: