自动布局中断 UIView 动画

Posted

技术标签:

【中文标题】自动布局中断 UIView 动画【英文标题】:Autolayout breaks UIView Animation 【发布时间】:2012-12-14 17:32:04 【问题描述】:

努力让我的应用同时在 iPhone 5 和较小的 iPhone 上运行。很高兴需要 ios6 并使用 Autolayout,因为这样效果很好。

但是,该应用程序有 4 个按钮会定期交换位置,因此我为每个按钮分配了与数组不同的位置,然后使用以下内容为移动设置动画:

[UIView animateWithDuration:0.5 animations:^
    button1.center = [[locations objectAtIndex:0] CGPointValue];
    button2.center = [[locations objectAtIndex:1] CGPointValue];
    button3.center = [[locations objectAtIndex:2] CGPointValue];
    button4.center = [[locations objectAtIndex:3] CGPointValue];
];

这不适用于自动布局。没有什么变化。我得到的最好的结果是它会动画到一个位置然后立即弹回。

当我移除 Autolayout 时,所有按钮在较小的 iPhone 上都被压缩了,而且因为我使用的是由 iPhone 5 尺寸设置的点,所以它们最终会降低,将底部的一行从屏幕上移开。我最初从 Interface Builder 获得了不同的 CGPoint 数字,但它们是“错误的”,尽管我认为它们是“错误的”,因为它们是 Autolayout 使用的数字。数组,你可以看到:

buttonLocations = [NSArray arrayWithObjects:
        [NSValue valueWithCGPoint:CGPointMake(57, 523)],
        [NSValue valueWithCGPoint:CGPointMake(109, 523)],
        [NSValue valueWithCGPoint:CGPointMake(57, 471)],
        [NSValue valueWithCGPoint:CGPointMake(109, 471)],
        nil];

我应该怎么做才能解决这个问题?为每个尺寸的设备设置不同的点似乎效率不高。

【问题讨论】:

【参考方案1】:

解决方案是为项目变换属性设置动画,而不是其位置。

位置将由自动布局设置,您不想与之抗争。然而,屏幕上的实际位置将是它的“正确”(由自动布局设置)位置,由它的 transform 属性偏移。

所以你可以说 button.transform = CGTransformMake(x,y) 它会出现 x 和 y 偏离它的中心位置。

有多种 CGWhatever 宏可以轻松进行这些变换,您只需在动画块中更改它们即可移动项目。

【讨论】:

我遇到了这个问题:Assigning to 'CGAffineTransform' (aka 'struct CGAffineTransform') from in compatible type 'int'? button.transform 的类型是什么?它应该是 CGAffineTransform。您正在分配 CGAffineTransformMakeTranslation() 或其他产生 CGAffineTransform 的函数的输出,对吗?看起来你正在尝试传递一个 int。 CGAffineTransform 产生一个变换。【参考方案2】:

一种方法是使用自动布局系统,并为约束的“常量”值设置动画。在下面的示例代码中,我在水平行中有三个按钮,每个按钮都有一个对超级视图的前沿约束,这就是我制作的动画。 side1、side2 和 side3 是这些约束的 IBOutlets,而 button1、button2 和 button3 是 3 个按钮的出口。

-(void)animateButton 
    [self.view removeConstraint:self.side1];
    [self.view removeConstraint:self.side2];
    [self.view removeConstraint:self.side3];

    NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:self.button1 attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:114];
    NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:self.button2 attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:213];
    NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:self.button3 attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:20];

    [self.view addConstraints:@[con1,con2,con3]];
    [UIView animateWithDuration:2 animations:^
        [self.view layoutIfNeeded];
    ];

【讨论】:

如果 button1、button2 和 button 3 是界面生成器中 UIButtons 的 IBOutlets,我将如何在项目中设置 side1、side2 和 side3? @WilliamRobinson,当您将按钮添加到视图时,将自动添加约束。不过,您可能必须更改它们。如果按钮全部垂直排列并且设置了明确的大小或设置为使用内在内容大小,那么他们应该需要的唯一其他约束将是超级视图的前沿——如果有任何其他约束(比如从后沿) 你可以删除它们。一旦你有了正确的约束,你就可以像任何其他对象一样将插座连接到它们。 当我单击 UIButton 并在 Utilities 视图中单击标尺并查看一长串内容时会出现这种情况,例如:“约束”“高度等于:50”,“对齐前导:按钮 -4 “等等? @WilliamRobinson,这是您看到它们的地方,但您必须在工作区左侧的对象列表中建立连接。如果单击包含这些按钮的视图的显示三角形,则应该有一个约束条目。【参考方案3】:

您只需对代码进行很少的更改即可解决此问题。与其交换按钮位置,不如交换它们的布局约束。您可以使用 cocoapod SBP 通过导入此类别来交换布局约束

    #import "UIViewController+SBP.h"

那就用这个方法

    - (void)switchViewConst:(UIView*)firstView secondView:(UIView*)secondView durationInSeconds:(double)durationInSeconds

Here is a video tutorial。

【讨论】:

以上是关于自动布局中断 UIView 动画的主要内容,如果未能解决你的问题,请参考以下文章

UIView animateWithDuration 动画块之外的动画自动布局视图

快速使用自动布局时为 UIView 高度设置动画

setNeedsDisplay 打破 UIView 的自动布局动画

如何使用自动布局在 UIScrollView 中为视图高度设置动画?

使用自动布局约束在 UIScrollView 内为 UIView 设置动画

使用自动布局时如何将动画从一个 UIView 翻转到另一个?