【问题标题】:MotionLayout ignores paddingMotionLayout 忽略填充
【发布时间】:2020-05-15 12:17:22
【问题描述】:

我正在尝试在滑动时为 textview 的边距、填充和 alpha 设置动画。 开始时,textview 没有填充,alpha 为 1。 最后,我希望 alpha 为 0,padding 为 100dp,边距为 16dp dp,alpha 为 0.5 一切正常,除了填充没有改变。 MotionLayout 是否支持填充? 我正在使用 androidx.constraintlayout:constraintlayout:2.0.0-beta4。

添加更多文本,因为 SO 说我的帖子看起来主要是代码... 添加更多文本,因为 SO 说我的帖子看起来主要是代码...... 添加更多文字,因为 SO 说我的帖子看起来主要是代码......

布局xml:

    <androidx.constraintlayout.motion.widget.MotionLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layoutParent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/test">

    <TextView
        android:id="@+id/fakenavigationBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="hello world">
    </TextView>
</androidx.constraintlayout.motion.widget.MotionLayout>

运动场景:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@id/fakenavigationBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:alpha="1"
            android:padding="100dp"
            motion:layout_constraintTop_toTopOf="parent"
            motion:layout_constraintStart_toStartOf="parent">
        </Constraint>

    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@id/fakenavigationBar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="16dp"
            android:alpha="0.5"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintBottom_toBottomOf="parent">
        </Constraint>

    </ConstraintSet>

    <Transition
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/end"
        motion:duration="2000"
        motion:motionInterpolator="linear">

        <OnSwipe
            motion:touchAnchorId="@+id/fakenavigationBar"
            motion:touchAnchorSide="top"
            motion:dragDirection="dragDown"/>
    </Transition>
</MotionScene>

【问题讨论】:

  • 如果您解释您想要实现的目标或分享屏幕截图,也许其他人会更理解
  • 我在问题中添加了更多细节。
  • 这里有人吗?像真的一样,有人吗?我该怎么做才能让人们看到这篇文章并帮助我?

标签: android animation padding android-motionlayout


【解决方案1】:

这是 MotionLayout 的限制

Padding 不是受支持的属性 ConstraintSet,因此不支持它。 View setPaddingTop 上甚至没有方法,因此它们不能被视为自定义属性。

这是 MotionLayout 中的一个空白,但存在填充问题。填充会更改视图测量尺寸,该尺寸会随着视图尺寸的变化而请求布局。 这很昂贵,因为解析动画的唯一方法是解析开始和结束约束集并重建插值。

最好重新设计布局以使用边距,因为这是布局的控制。

【讨论】:

    【解决方案2】:

    这是可能的,但显然会带来很大的性能成本。

    MotionLayout.TransitionListener 添加到您的MotionLayout,计算给定进度值(0f-1f)的正确填充值,并将其设置到onTransitionChange() 中的视图:

    motionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
        override fun onTransitionStarted(motionLayout: MotionLayout, startId: Int, endId: Int) { }
    
        override fun onTransitionChange(motionLayout: MotionLayout, startId: Int, endId: Int, progress: Float) {
            val paddingInPx = calculatePaddingPx(progress)
            myView.setPadding(paddingInPx, paddingInPx, paddingInPx, paddingInPx)
        }
    
        override fun onTransitionCompleted(motionLayout: MotionLayout, currentId: Int) { }
    
        override fun onTransitionTrigger(motionLayout: MotionLayout, triggerId: Int, positive: Boolean, progress: Float) { }
    })
    

    在您的MotionScene 中,添加:

    &lt;Transition motion:layoutDuringTransition="honorRequest"/&gt;

    另请参阅:https://github.com/androidx/constraintlayout/issues/7#issuecomment-721447209

    编辑 1:虽然我能够使用这种技术更改填充,但我最终决定不使用它,因为在旧设备上性能影响非常明显。

    编辑 2:还有一个与滚动动画相关的问题,如果你做一个 fling,则不能保证调用 TransitionListener 回调,所以转换将在没有的情况下达到它的开始/结束状态更新了填充。

    【讨论】:

      【解决方案3】:

      我承认这不是一个很有帮助的答案,但我在填充方面遇到了同样的问题。边距似乎适用于 MotionLayout,但它似乎不支持填充。我所做的让我的工作有点像我想要的是将我的 MotionLayout 文件中的填充添加到我想要的任何视图中。它尊重该文件中的填充,但不尊重运动场景约束集中的填充,因此在我的情况下它无法为填充设置动画。它只会保留在 MotionLayout 文件中设置的静态填充,这对我来说已经足够了。

      this blog post 看来,如果您将动态场景转换设置为两个不同的布局之间而不是约束集,您可能会在填充之间设置动画。

      我向几个不同的资源提出了一个问题,即为什么 MotionLayout 不支持填充,如果我得到任何有用的信息,我会更新我的答案,但据我所知,MotionLayout 不支持动画填充值。

      【讨论】: