【问题标题】:How to specify TransitionManager.beginDelayedTransition to affect only direct child views如何指定 TransitionManager.beginDelayedTransition 仅影响直接子视图
【发布时间】:2018-05-21 22:21:39
【问题描述】:

我正在尝试将ConstraintLayout 与随着动画上下滑动的视图结合使用。 这些视图是垂直组织的,顶部有一个RecyclerView,下面堆叠了另外两个视图:

<constraint layout container>
    [                    ]
    [    recycler view   ] 
    [                    ]
    [48dp height 1st view]
    [48dp height 2nd view]
</constraint layout container>

动画非常简单:当一个按钮被点击时,第一个视图从容器底部移动到您可以在上面看到的位置,当再次点击时,它向下移动并保持重叠在第二个视图上。发生这种情况时,顶部的 RecyclerView 会更改高度,因为它被限制在第一个视图中,否则它将留下一个空白空间。

到目前为止一切顺利,动画运行良好,但是当用户点击按钮过快时会出现问题,导致以下错误:

    java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

在调查了发生的情况后,我发现这个问题是我用来为更改设置动画的TransitionManager 造成的。我发现很有趣,当点击按钮向上(或向下,想象相反的步骤)移动第一个视图时,经理正在执行以下操作:

  • RecyclerView 中淡出第一个/最后一个视图(取决于您是否启用了反向布局或堆栈)
  • RecyclerView 中删除该视图
  • 降低RecyclerView的高度
  • 上移第一个视图

即使我在所有我能想象到的地方都指定了 RecyclerView 不应该为项目更改设置动画,但 TransitionManager 覆盖了它,这意味着当同一视图即将被删除时会有一个窗口从RecyclerView 可以再次添加到同一个父级,并且该窗口是当视图被管理器淡出时。

由于淡入淡出动画不是那么快,用户可以很容易地在此期间点击按钮两次,导致管理器重新添加淡入淡出视图,该视图已经在 RecyclerView 中,从而导致应用程序崩溃抛出上述错误。

由于这是在 RecyclerView 内部引起的问题,因此如果其中没有动画,我会非常好,因此我想知道如何在 TransitionManager.beginDelayedTransition 中指定仅动画直接子视图ConstraintLayout,这样它就不会为 RecyclerView 内的视图设置动画。

相关文档对此没有任何帮助,所以我在这里提出这个问题;如何将转换限制为直接子视图?

如果有帮助,我会在此处包含转换管理器的 sn-p

    final ConstraintSet constraintSet;
    final ConstraintLayout constraintLayout;

    constraintSet = new ConstraintSet();
    constraintLayout = (ConstraintLayout) viewParent;

    TransitionManager.beginDelayedTransition(constraintLayout);

    constraintSet.clone(constraintLayout);
    constraintSet.connect(startId, startSide, endId, endSide, margin);
    constraintSet.applyTo(constraintLayout);

【问题讨论】:

  • 使用TransitionManager.beginDelayedTransition 的两个参数版本并传递一个排除您的某些视图的Transition
  • @pskink TransitionSet 有一种方法可以忽略子视图,谢谢。您可以发布答案以便我接受吗?
  • Transition 有这样的方法:Transition#excludeTarget / Transition#excludeChildren / Transition#removeTarget
  • @pskink 我知道,多亏了您的评论才找到它,这就是为什么我要求您将其发布为我接受它的答案,因为不允许接受 cmets答案。

标签: android android-recyclerview android-transitions


【解决方案1】:

pskink 在 cmets 中发布了答案,但在两次要求他发布作为我接受但从未这样做的答案后,我将其发布并标记为已回答。

TransitionManager 有一个方法 excludeChildren 非常适合我正在寻找的东西。您可以按类类型、特定视图的子项等使用。

编辑:添加请求的示例

    AutoTransition autoTransition = new AutoTransition();
    autoTransition.excludeChildren(R.id.recyclerView, true);
    TransitionManager.beginDelayedTransition(constraintLayout, autoTransition);

constraintLayout 作为目标视图的父视图,R.id.recyclerView 是我不想动画的父视图的子视图,在这个具体的例子中就是这样。您还可以排除属于特定类别的所有孩子(例如EditText)等等。

【讨论】:

  • 感谢您的示例。但正如我所说,使用 AutoTransition 改变了没有它时 ConstraintLayout 生成的默认动画,所以我不能使用它。
  • @KashishMalhotra 对此很抱歉,但这是我用于解决我遇到的问题的代码。如果它对您的情况不起作用,最好发布一个与此相关的新问题,以便其他人可以尝试帮助您。
  • 成功了。我犯了一个非常愚蠢的错误。调试代码后,您的解决方案运行良好。谢谢!
  • 太棒了,谢谢。这里也相关:stackoverflow.com/a/59355664/3763032 所以我也参考了这个答案
  • 在我的情况下 excludeChildren 不起作用,我使用 excludeTarget 代替
【解决方案2】:

我是这样解决的:

TransitionManager.beginDelayedTransition(
                        constraintLayout,
                        TransitionSet().apply {
                            ordering = TransitionSet.ORDERING_SEQUENTIAL
                            addTransition(ChangeBounds())
                            addTransition(Fade(Fade.IN))
                        }
                    )

AutoTransition 内部的代码几乎相同,如果我们不通过自定义转换,这是默认代码,但我删除了似乎是导致崩溃的原因的 addTransition(Fade(Fade.OUT))。至少对我来说,动画看起来与原版非常相似。

【讨论】:

  • 非常感谢。 TransitionSet.ORDERING_TOGETHER 在地图相机移动或空闲时为我的谷歌地图上的覆盖小部件设置动画。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
  • 1970-01-01
  • 2015-09-19
  • 1970-01-01
  • 1970-01-01
  • 2015-05-24
  • 1970-01-01
相关资源
最近更新 更多