xcode6开始,写界面基本都是用size classes +layoutContraint了,对于一般的静态页面,使用constrain简单快速还能支持横竖屏切换,high到爆!
使用constraint实现的页面在viewDidAppear之后,想做什么动画也可以,虽然有约束在,但是只要不去调用setNeedUpdateConstraint就没问题。
本着这样的思想,我用约束实现了带有输入框的约束,在键盘弹起的时候,使用UIView级别的动画跟这键盘同步。
先上storyboard拖出来的界面:
再来添加viewController.m中的相关方法:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"viewWillAppear");
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
NSLog(@"viewWillDisappear");
}实现键盘方法:
-(void)keyboardWillChangeFrame:(NSNotification*)noti
{
NSLog(@"userInfo = %@",noti.userInfo);
CGFloat y = CGRectGetMaxY(self.textField.bounds);
CGRect keyRect = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
if (y == CGRectGetMinY(keyRect)) {
NSLog(@"return....");
return;
}
[UIView animateWithDuration:[noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
animations:^{
self.textField.frame = CGRectMake(CGRectGetMinX(self.textField.frame), CGRectGetMinY(keyRect) - CGRectGetHeight(self.textField.frame), CGRectGetWidth(self.textField.frame), CGRectGetHeight(self.textField.frame));
}
completion:^(BOOL finished) {
NSLog(@"animate bottom = %lf",CGRectGetMaxY(self.textField.frame));
}];
}键盘弹起时,捕获键盘弹起动画时间,键盘miny来设置textfield的frame
本来以为大功告成的,但是,看下图:
这是什么鬼?完全没有按照原来设想的走,红色的label闪了下,感觉整个view好像刷新了一次。难道是上边的设想不对?添加了约束的view不能再更改frame?
赶紧做个试验测试下:
添加以下代码测试:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"viewDidAppear");
[UIView animateWithDuration:0.3f
animations:^{
self.label.center = CGPointMake(300, 400);
}
completion:^(BOOL finished) {
}];
}测试效果:
这个效果完全符合我们之前的设想,约束更新之后完全可以更改frame的。出现之前的view刷新的情况应该是出发了self.view 的setNeedUpdateConstraints.
再来测试下效果:
修改viewDidAppear
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"viewDidAppear");
[UIView animateWithDuration:0.3f
animations:^{
self.label.center = CGPointMake(300, 400);
}
completion:^(BOOL finished) {
NSLog(@"animate bottom = %lf",CGRectGetMaxY(self.textField.frame));
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.view setNeedsUpdateConstraints];
for (NSLayoutConstraint* constraint in self.view.constraints) {
if ([constraint.firstItem isEqual:self.label] && [constraint.secondItem isEqual:self.view]) {
NSLog(@"constraint constant = %lf",constraint.constant);
}
}
});
}];
}效果图:
现在猜想,因为是键盘弹出触发了当前view 的setNeedsUpdateContraints.
如果是触发了更新约束,那只能更新textfield的约束了。
测试下,修改keyboardwilchange的方法:
-(void)keyboardWillChangeFrame:(NSNotification*)noti
{
NSLog(@"userInfo = %@",noti.userInfo);
CGFloat y = CGRectGetMaxY(self.textField.bounds);
CGRect keyRect = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
if (y == CGRectGetMinY(keyRect)) {
NSLog(@"return....");
return;
}
for (NSLayoutConstraint* constraint in self.view.constraints) {
if ([constraint.firstItem isEqual:self.bottomLayoutGuide] && [constraint.secondItem isEqual:self.textField]) {
NSLog(@"update constraint success");
constraint.constant = CGRectGetMinY(keyRect) == CGRectGetHeight(self.view.bounds) ? 0.f: CGRectGetHeight(keyRect);
}
}
[UIView animateWithDuration:[noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
animations:^{
[self.view setNeedsUpdateConstraints];
}
completion:^(BOOL finished) {
NSLog(@"animate bottom = %lf",CGRectGetMaxY(self.textField.frame));
}];
}效果图:
效果是差不多实现了,但是不完美,说好的同步上移呢
修改animation Block 如下:
-(void)keyboardWillChangeFrame:(NSNotification*)noti
{
NSLog(@"userInfo = %@",noti.userInfo);
CGFloat y = CGRectGetMaxY(self.textField.bounds);
CGRect keyRect = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
if (y == CGRectGetMinY(keyRect)) {
NSLog(@"return....");
return;
}
for (NSLayoutConstraint* constraint in self.view.constraints) {
if ([constraint.firstItem isEqual:self.bottomLayoutGuide] && [constraint.secondItem isEqual:self.textField]) {
NSLog(@"update constraint success");
constraint.constant = CGRectGetMinY(keyRect) == CGRectGetHeight(self.view.bounds) ? 0.f: CGRectGetHeight(keyRect);
}
}
[UIView animateWithDuration:[noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
animations:^{
[self.view layoutIfNeeded];
}
completion:^(BOOL finished) {
NSLog(@"animate bottom = %lf",CGRectGetMaxY(self.textField.frame));
}];
}
效果图:
OK,大功告成!!哈哈!!
本文介绍了在Xcode6及以上版本中,利用Size Classes和NSLayoutConstraint进行界面布局,并在键盘弹起时,通过监听键盘动画时间同步调整UITextField的位置,以避免键盘遮挡输入框。在实现过程中,遇到视图刷新问题,通过实验验证了约束更新后仍可修改frame。最终通过修改animation block成功实现了键盘同步上移的效果。
777

被折叠的 条评论
为什么被折叠?



