【问题标题】:animateLayoutChanges does not work well with nested layout?animateLayoutChanges 不适用于嵌套布局?
【发布时间】:2013-12-04 21:57:17
【问题描述】:

我有一个嵌套布局,如下所示:

 <LinearLayout>     <!----Parent layout--->
    <LinearLayout>    <!-----child 1--->
       ...
    </LinearLayout>   <!----child 1 ended--->
    <LinearLayout>    <!-----child 2--->
       ...
    </LinearLayout>   <!----child 2 ended--->
 </LinearLayout>    <!----Parent endded--->

我现在遇到的问题是,由于我的所有数据项都在子 1 或子 2 Linearlayout 内,如果我添加或删除一个项目,子线性布局将使用 animateLayoutChanges 的效果进行动画处理,但父布局不会做任何动画。 (对于所有线性布局,我将android:animateLayoutChanges 设置为true)。特别是当我删除孩子 1 中的一个项目时,动画效果变得很奇怪(基本上孩子 2 会跳起来,而孩子 1 仍在做动画)。

有人知道如何解决这个问题吗?

谢谢

更新

在我发布这个问题后不久,我在 LayoutTransition API 的 android 开发者网站上找到了这个。

在嵌套视图层次结构的多个级别上使用 LayoutTransition 可能无法正常工作,因为各个级别的布局之间存在相互关系。

那么有人对此问题有任何解决建议吗?

【问题讨论】:

    标签: android android-layout android-animation


    【解决方案1】:

    animateLayoutChanges 属性使用LayoutTransitions,它为布局的子级以及从 Android 4.0 开始的布局层次结构中的祖先设置动画,一直到树的顶部。在 Honeycomb 中,只有布局的子元素会被动画化。详情请见this Android Developers Blog post

    不幸的是,目前似乎没有简单的方法让布局的兄弟姐妹对其LayoutTransitions 做出反应。您可以尝试使用TransitionListener 在布局边界发生更改时收到通知,并使用动画器相应地移动同级视图。请参阅 Chet Haase 在this Google+ post 中的第二个答案。

    EDIT - 原来是 一种方法。在 Android 4.1+(API 级别 16+)中,您可以使用布局转换类型 CHANGING,默认情况下禁用。在代码中启用它:

    ViewGroup layout = (ViewGroup) findViewById(R.id.yourLayout);
    LayoutTransition layoutTransition = layout.getLayoutTransition();
    layoutTransition.enableTransitionType(LayoutTransition.CHANGING);
    

    因此,在您的示例中,要为子 2 布局设置动画,您需要为其启用 CHANGING 布局转换。当其父对象的边界发生变化时,将应用转换。

    更多详情请见this DevBytes video

    【讨论】:

    • 我确实尝试过,但在我的情况下它并不能很好地工作,我认为将 enableTransitionType 设置为更改与将 animateLayoutChanges 标志设置为 true 具有类似的效果。无论如何,我转向了另一种方法,因此不再需要动画嵌套布局。
    • @Vijju 我放弃了这种设计并采取了不同的方法。从我读过的文档来看,我认为这不容易做到,所以我猜你要么必须在没有这个小动画的情况下构建,要么自己编写过渡。
    • 使用 LayoutTransition.enableTransitionType(LayoutTransition.CHANGING) 就像一个魅力!谢谢!
    • layoutTransition.enableTransitionType(LayoutTransition.CHANGING);确实适用于嵌套布局,只需将其添加到您的父布局即可。但是,消失的视图将不同步,您会看到,当您查看视图时,父布局将先于子布局完成。要解决此问题,您还需要修改子布局转换并设置 layoutTransition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);通过这样做,出现和消失将与父母和孩子同步。
    • @chronogenre setStartDelay 确实在两个转换之间同步,但消失的视图正在消失在它旁边移动的孩子身上。有没有办法在淡出完成后开始 CHANGING 运动?
    【解决方案2】:

    好的,在消化了第一个答案之后,我在这里简单说一下,对于那些在 NESTED 布局中使用android:animateLayoutChanges="true" 时没有得到正确动画效果的人:

    1. 确保将android:animateLayoutChanges="true" 添加到will-be-resized ViewGroup (LinearLayout/RelativeLayout/FrameLayout/CoordinatorLayout)。

    2. 使用setVisibility() 控制目标 View 的可见性。

    3. 从这里仔细听,android:animateLayoutChanges="true"添加到您的will-be-resizedViewGroup外部ViewGroup,这个外层 ViewGroup 一定是包裹了所有受动画影响的位置变化View 的那个。

    4. setVisibility()之前的Activity中添加以下代码,这里rootLinearLayout是我上面提到的外部ViewGroup

       LayoutTransition layoutTransition = rootLinearLayout.getLayoutTransition();
       layoutTransition.enableTransitionType(LayoutTransition.CHANGING);
      

    之前:

    之后:


    提醒:如果错过第三步,会出现空指针异常。

    祝你好运!

    【讨论】:

    • 感谢您的详细解释!
    • 感谢您为包含 GIF 所做的努力。非常感谢。 +1
    • 你太棒了,非常感谢
    • 如果您快速单击视图会怎样?过渡动画是否仍按预期工作而不闪烁?
    【解决方案3】:

    我们已将 android:animateLayoutChanges 属性添加到 LinearLayout,但更改并未触发动画。要解决这个问题,请使用以下代码:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    ((ViewGroup) findViewById(R.id.llRoot)).getLayoutTransition()
          .enableTransitionType(LayoutTransition.CHANGING);
    }
    

    More details.

    【讨论】:

      【解决方案4】:

      作为 Kotlin 扩展

      fun ViewGroup.forceLayoutChanges() {
          layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
      }
      

      用法

      someContainer.forceLayoutChanges()
      

      注意事项:

      根据我的经验,当容器是深层嵌套布局时会发生这种情况。出于某种原因,android:animateLayoutChanges="true" 不起作用,但使用此功能将强制它工作。

      【讨论】:

      • 让我成为第四个为您的答案投票的人。不仅仅是魅力! :)
      • @MakariKevin ?乐于助人!
      【解决方案5】:

      似乎父级上的延迟过渡也适用于动画。至少对我来说,以下代码给出了正确的展开/折叠动画。

      expandTrigger.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View v) {
              TransitionManager.beginDelayedTransition(parentLayout);
              expanded = !expanded;
      
              child1.setVisibility(expanded ? View.VISIBLE : View.GONE);
          }
      });
      

      对于深度嵌套的布局,您有时可能需要在调用TransitionManager 时使用层次结构中较高的父级。

      【讨论】:

      • 这实际上是我唯一可以调整 PopUpWindow 大小的方法(通过它的更新方法)
      【解决方案6】:

      我也有类似的问题:

      我在我的一个活动中使用了 animatelayoutchanges 与回收器视图,我还添加了一些自定义布局转换,因为我想在一个项目消失在列表中时提高动画的速度。当它不在嵌套布局中时,它工作正常。

      我在嵌套布局中的另一个 recyclerview 中使用了相同的适配器。它不起作用,我尝试了上述所有解决方案,但没有一个对我有用。

      真正的原因是,我忘了设置

      mTicketsListAdapter.setHasStableIds(true);
      

      在嵌套布局活动中。将 setHasStableIds 设置为 true 后,动画在嵌套布局中完美运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-15
        • 2020-04-24
        • 1970-01-01
        • 2023-02-16
        • 2021-06-26
        • 1970-01-01
        相关资源
        最近更新 更多