iOS键盘与NSLayoutConstraint

xcode6开始,写界面基本都是用size classes +layoutContraint了,对于一般的静态页面,使用constrain简单快速还能支持横竖屏切换,high到爆!

使用constraint实现的页面在viewDidAppear之后,想做什么动画也可以,虽然有约束在,但是只要不去调用setNeedUpdateConstraint就没问题。

本着这样的思想,我用约束实现了带有输入框的约束,在键盘弹起的时候,使用UIView级别的动画跟这键盘同步。

先上storyboard拖出来的界面:

iOS键盘与NSLayoutConstraint_第1张图片

再来添加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,大功告成!!哈哈!!













你可能感兴趣的:(keyboard)