如何使用自动布局动画视图更改视图层次结构?

Posted

技术标签:

【中文标题】如何使用自动布局动画视图更改视图层次结构?【英文标题】:how to animate views change views hierarchy using autolayout? 【发布时间】:2013-04-24 18:14:35 【问题描述】:

我有一个名为 self.myMainView 的超级视图

在那个视图中,我有三个子视图:UIView *view1(绿色视图)、UIView *view2(灰色视图)、UIImageView *view3

我想动画视图 3 的移动

当视图 3 完成后,我想要更改视图层次结构,例如屏幕截图。

这里是示例图片:

【问题讨论】:

@matt 这个图像视图例如,这有什么价值?视图 3 的行为可能不正确? 以便我可以尝试重现该问题。正在努力... 嘿,马特,如果你能帮助我,我可以为你制作一个包含所有有价值代码的模型,你需要这个吗? 不,我已经重现了这个问题!你的描述很好。现在我正在寻找解决方案... 我想通了!这是因为您在情节提要中启用了自动布局 【参考方案1】:

您正在做的是更改视图分层顺序的正常标准方法。所以问题不在于这个,而用你的话来说“但是,它违反了我的动画”和“粉碎我的动画”。那么,问题在于你的动画,如果它可以通过重新排列图层来“违反”和“粉碎”。但是,在您的问题中,您没有提供有关动画的任何信息!然而,这显然是问题的核心。

编辑:既然您已经发布了动画代码,我就可以进行测试了,我明白了问题所在。问题是您使用的是自动布局。

view3 由约束定位。当您为view3 的位置设置动画时,您违反了这些约束,但这不会立即变得明显。但是当你交换view1view2的分层顺序时,就会进行布局!然后强制执行view3 上的约束。由于这些限制没有改变,我们看到 view3 回到原来的位置。

最简单的解决方案是在不需要时关闭自动布局。否则,您将不得不在动画之后或作为动画的一部分更改约束。事实上,您可以通过动画其位置约束来重新定位view3。我在我的书中描述了这一切,在这里:http://www.apeth.com/iosBook/ch17.html#_animation_and_autolayout

【讨论】:

谢谢!)昨天我读了你书中关于观点的一章:)谢谢你的工作,你做得很好! 希望本书的这一部分对你有所帮助。它以与您的示例非常相似的示例开始,其中视图“跳回”到它开始的位置。然后我给出了各种解决方案。 你好,马特,我想问你关于你书中代码中的一个问题,我使用的代码是动画定位视图的约束的变化,这里的代码有这个问题并抛出异常:Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 128552240 beyond bounds [0 .. 17]' 代码是:NSUInteger indexOfconstraintsAttribute = [constraintsForAnimation indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)... xcode 担心类型 NSUInteger 一定是 NSIndexSet 为什么? 我在之前的评论中犯了一个错误,在我的代码中,我将indexesOfObjectsPassingTest: 更改为indexOfObjectPassingTest:,但Xcode 仍然抛出异常。同样的错误:2013-04-25 18:05:31.948 MyFirstApp[8676:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 2147483647 beyond bounds [0 .. 18]'我不知道出了什么问题 cmets 不是第二个问题的好地方;相反,只需提出一个新问题!这样您就可以正确显示您的代码等。【参考方案2】:

如果您只想切换 2 个子视图中的哪一个在另一个之上,您可以简单地使用 [UIView bringSubviewToFront:] 而不是直接弄乱您的子视图数组的顺序吗?这可能会解决动画问题。我会尝试的另一件事是在您对exchangeSubviewAtIndex 的调用周围加上if( finished ),以确保它不会干扰其他动画视图。

【讨论】:

bringSubviewToFront 不适合我的目的,我已经尝试过了,但我现在会尝试if(finished) 嗯好吧,我会四处寻找,看看能不能找到解决办法。 没问题!很高兴你把它整理好了。【参考方案3】:

问题在于视图 3 的约束在动画后不会改变,当我们想要操纵视图层次结构时,动画会停止正常工作。马特在他的回答中谈到了这一点,他还从他的好书中提供了一个解决方案:http://www.apeth.com/iOSBook/ch17.html#_animation_and_autolayout 谢谢你的那个马特。

我稍微更改了此解决方案,并决定将其发布在此处以供需要此解决方案的任何人使用。但如果你想更好地理解这一点,我强烈建议你阅读书中关于动画的章节,链接在上面。

首先,我们需要为视图 3 的移动设置动画,然后更改我们的约束,并且只有在此之后才更改视图层次结构。在书中找到了几种方法来做到这一点,但在我看来这是最好的:

layout = -35.0; //  new constraint constant of self.view3

NSArray *constraintsForAnimation = self.myMainView.constraints; // all constraints of superview 

NSUInteger indexOfconstraintsAttribute = [constraintsForAnimation
indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) // get index of constraint of view 3

    NSLayoutConstraint *constraint = obj;


    return (([constraint.firstItem isEqual: self.view3])) ? idx : NO; // return this index if we found constraint of view 3

];


constraint.constant = layout; // changing the constraint of view3 

[UIView animateWithDuration:0.3 animations:^ // animation
   [self.view3 layoutIfNeeded]; // apply new constraints to view3
];


[self.myMainView exchangeSubviewAtIndex:3 withSubviewAtIndex:4];// toggle view 1 with view 2

我们仅在约束的帮助下移动视图 3,我们不设置框架或中心视图属性。 好的,我们完成了,这就像我想要的那样工作。希望这对您也有帮助。

【讨论】:

以上是关于如何使用自动布局动画视图更改视图层次结构?的主要内容,如果未能解决你的问题,请参考以下文章

uiscrollview的自动布局,视图层次结构没有为约束做好准备

使用 XIB 和自动布局操作视图层次结构

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

错误:线程 1:“无法设置未准备好约束的视图层次结构的布局。”使用自动布局时

如何使用自动布局动态更改超级视图的高度

设备方向更改时如何重新排列集合视图单元格