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,大功告成!!哈哈!!