gpt4 book ai didi

ios - UIView中复杂的布局,可对其内容进行动画处理

转载 作者:行者123 更新时间:2023-11-29 12:43:27 31 4
gpt4 key购买 nike

当我设计同时需要特殊布局和动画的复杂UIView时,我经常遇到这个问题。

我当前正在构建的是与iOS上的Mail应用程序用来在编写电子邮件(蓝色徽章容器)时显示收件人列表的视图相同的视图:

因此,我理解并知道如何构建这样的视图,但是面对这种情况时,我总是会遇到一个问题:如何同时处理复杂的布局(对所有蓝色圆角矩形进行布局)及其动画(添加时或删除收件人)?

1.通常我会重新实现:

- (void)layoutSubviews

以根据我的当前边界在布局时刻(即,将每个蓝色圆形的UIButton并排布置)反映视图的状态,并且当有人向列表中添加新人员时,只需添加一个UIButton并为其设置动画即可。

但是,如果已经运行了布局传递,动画将发生什么? (这可能是一个愚蠢的问题,因为所有事情都应该在主线程上发生,因此这里不涉及并发,但是我不确定如何处理)

我认为这两个事情(布局和动画)不应该同时发生,因为主要的运行循环“一次入队,而出队入场”一次一个“块”(但一个动画可能只有数百个块入队)绘制不同的东西,这很容易被介于两者之间的布局块所折衷?)

2.另外,此解决方案是否可以接受?
  • 重新实现layoutSubviews以完全相同的方式处理我的子视图的正确布局
  • 当某人添加或删除某人时,只需调用此按钮即可重新放置所有已设置动画的位置
    [UIView animateWithDuration:0.25f animations:^{
    [self setNeedsLayout];
    [self layoutIfNeeded];
    }];

  • 如您所见,这里有很多问题,我不知道该如何优雅地处理。

    这两种解决方案都已经过测试和批准,但是哪个是最好的呢?

    您有更好的解决方案吗?

    谢谢你的帮助!

    最佳答案

    据我了解,您的意思是将动画应用于应用了layoutSubviews方法的视图,例如动画更改其框架。如果在动画进行过程中视图中的某些更改导致视图重新布局,则将调用layoutSubviews方法。

    基本上,这种动画只不过是以下内容:

  • 将视图的框架(实际上是视图图层的框架)更改一些较小的值(例如,将原点的Y坐标增加1个像素)
  • 调用layoutSubviews,如果需要
  • 重绘视图(即其图层)
  • 通过一些小的值
  • 更改视图的框架
  • 调用layoutSubviews,如果需要
  • 重绘视图
  • ...
  • 重复上述步骤,直到视图的属性达到目标值为止

  • 所有这些步骤都是在主线程上执行的,因此上述步骤是连续的,而不是并行的。

    一般而言, layoutSubviews方法应基于其自身的边界来定义子视图的坐标和大小。动画会更改视图的框架及其边界,因此,实现 layoutSubviews方法应正确处理这些更改。

    也就是说,您问题的答案是正确实现 layoutSubviews方法。

    P.S. This answer很好地解释了动画的实现方式。

    更新资料

    似乎以前我不正确地理解了这个问题。我的理解是:

    如果为动画视图调用 layoutSubviews方法会怎样?
    也就是说,我假设有一些观点,例如使用动画更改其 y坐标,在动画过程中为此视图调用 layoutSubviews方法,并且该视图的某些子视图更改其在 layoutSubviews中的位置。

    经过@Nicolas的澄清后,我的理解如下:

    让我们来看一下带有子视图( 'Parent')的视图( 'Child');让我们为该子视图设置动画( 'Child');让我们调用 layoutSubviews视图的 'Parent'方法,并在进行动画时更改此 'Child'方法中 layoutSubviews子视图的帧。会发生什么?

    背景理论:
    UIView本身不呈现任何内容。它是由Core Animation层完成的。每个视图都有一个关联的 CALayer,其中包含一个视图的位图快照。实际上, UIView只是Core Animation Layer上方的一个薄组件,它使用视图的位图快照执行实际绘制。这种机制可以优化绘图:光栅化的位图可以通过图形硬件快速渲染;如果未更改视图结构,则位图快照将保持不变,即它们是“缓存的”。

    核心动画层层次结构与 UIView的层次结构匹配;也就是说,如果某个 UIView具有子视图,则对应于容器 UIView的Core Animation层将具有与该子视图对应的子层。

    好吧...实际上,每个 UIView甚至具有1个以上对应的 CALayerUIView层次结构生成3个匹配的Core Animation Layers树:
  • 层树-这些是我们过去通过UIViewlayer属性
  • 使用的层
  • 表示树-包含任何正在运行的动画的运行中值的图层。图层树对象包含动画的目标值,而表示树中的对象则反映屏幕上显示的当前值。您永远不要修改此树中的对象。相反,您可以使用这些对象读取当前动画值,也许可以从这些值开始创建新动画。
  • 渲染树中的对象执行实际的动画,并且是Core Animation专用的。

  • UIView属性的更改(例如框架)实际上是CALayer属性的更改。也就是说,UIView的属性是对应CALayer属性的包装。

    UIView框架的动画实际上是CALayer框架的变化。立即将“图层树”中图层的帧设置为目标值,而将时间延长“表示树”中图层的帧值的更改。以下调用:
    [UIView animateWithDuration:5个动画:^ {
    CGRect框架= self.label.frame;
    frame.origin.y = 527;
    self.label.frame =框架;
    }];
    并不意味着 self.labeldrawRect:方法在接下来的5秒钟内将被多次调用;这意味着与 y对应的表示树 CALayerself.label-坐标将在这5秒钟内从初始值逐渐更改为目标值,并且根据 self.label的更改将多次重绘此 CALayer中存储的 y的位图快照-坐标。

    回答:

    在这种背景下,现在我们可以回答原始问题。

    因此,我们正在为子视图进行动画处理,并为父视图调用 layoutSubviews方法;在这种方法中,子视图的框架会更改。这意味着与子视图关联的图层的框架将立即设置为新值。同时,表示树中的图层具有一些中间值(根据进行中的动画);设置新框架仅会更改表示树图层的目标值,以便动画将继续到达新目标。

    也就是说,原始问题中描述的情况的结果是“跳跃”动画。请在 GitHub sample project中查看演示。

    此类复杂案例的解决方案

    layoutSubviews方法中,如果正在进行动画,则需要使用飞行中的动画坐标。您可以使用与视图关联的 presentationLayerCALayer方法获得它们。也就是说,如果一个动画视图称为 aView,则可以使用 [aView.layer presentationLayer]访问该视图的表示层。

    关于ios - UIView中复杂的布局,可对其内容进行动画处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24279412/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com