iOS - 子视图不使用帧更改进行动画处理

Posted

技术标签:

【中文标题】iOS - 子视图不使用帧更改进行动画处理【英文标题】:iOS - Subview not Animating with Frame Change 【发布时间】:2014-10-02 20:44:45 【问题描述】:

我有一个视图,当键盘向上滑动时,我正在尝试为高度变化设置动画(代码如下所示)。我称之为帧变化的视图是完美的动画。但是,该视图包含一个子视图,该子视图又包含一个文本字段(导致键盘弹出),这些子视图只是跳转到它们的新位置而不是动画。我在子视图上放置了自动布局约束,以将其约束在父视图的左侧、底部和右侧,并保持恒定的高度。

此处的示例视频:http://youtu.be/EmcZ-cXeTbM

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slideViewForKeyboard:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slideViewForKeyboard:) name:UIKeyboardWillHideNotification object:nil];

- (void)slideViewForKeyboard:(NSNotification *)note 
    NSDictionary* userInfo = [note userInfo];

    // Get animation info from userInfo
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;    
    CGRect keyboardEndFrame;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];

    CGRect newFrame = CGRectMake(self.view.frame.origin.x,
                                 self.view.frame.origin.y,
                                 self.view.frame.size.width,
                                 keyboardEndFrame.origin.y);

    [UIView animateWithDuration:0 delay:0 options:(animationCurve << 16) animations:^
        [self.view setFrame:newFrame];
    completion:^(BOOL completed)];

- (IBAction)endEditingOnTap:(UITapGestureRecognizer *)sender 
    [self.view endEditing:YES];


@end

【问题讨论】:

【参考方案1】:

您应该使用animationDuration 作为动画块的持续时间。

除此之外,您还有另一个问题。现在,您在动画块内设置视图的框架,因此更改是动画的。但是系统稍后会在运行循环的布局阶段,在动画块之外布置子视图。这意味着子视图不会被动画到它们的新帧。

您可以通过将layoutIfNeeded 发送到动画块内的视图来解决此问题:

[UIView animateWithDuration:animationDuration delay:0 options:(animationCurve << 16) animations:^
    self.view.frame = newFrame;
    [self.view layoutIfNeeded];
 completion:^(BOOL completed)];

但是您可能会遇到另一个问题。您正在直接设置视图的框架,但您正在使用自动布局。在某些时候,自动布局可能会根据您的约束设置框架。您需要修改视图上的约束以控制其新框架,而不是直接设置框架。

【讨论】:

谢谢,-layoutIfNeeded 正是我所需要的。 (animationDuration 只是一个错字,因为我将代码切换到 SO,但也感谢您的发现!)【参考方案2】:

设置动画持续时间。

 [UIView animateWithDuration:0.3 delay:0 options:(animationCurve << 16) animations:^
            [self.view setFrame:newFrame];
        completion:^(BOOL completed)];

【讨论】:

【参考方案3】:

您将 0 传递给 -[UIView animateWithDuration:delay:options:animations:completion]。这不会产生动画,因为它从第 0 帧到第 n-1 帧(其中 n 是它会生成的帧数)在 0 秒内,也就是瞬时。尝试将您的 animationDuration 作为持续时间的参数传递,使其以与键盘相同的速度进行动画

【讨论】:

以上是关于iOS - 子视图不使用帧更改进行动画处理的主要内容,如果未能解决你的问题,请参考以下文章

如果父视图正在动画,则 IOS7 子视图会被动画

iOS:动画子视图而不调用 layoutSubviews

更改 UICollectionViewCell 子视图框架

动画 UIView 帧更改而不移动动画(即位置之间的交叉溶解)

UIView 使用自定义属性有条件地为子视图设置动画

iOS UITableViewCell 发布子视图