Android MotionLayout 在编程改变约束时状态未更新

10
我有一个非常简单的MotionLayout,我正在尝试通过编程方式更改其中一个约束的可见性,并使视图反映出该更改。但是,直到我从当前状态转换并回到它之前,更改才被反映出来。如何使视图立即根据新约束更新自身?我已经尝试过updateState()rebuildScene()invalidate(),但它们似乎都没有起作用。
以下是该视图:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
        android:id="@+id/motion_layout"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:showIn="@layout/activity_main"
        app:layoutDescription="@xml/motion_scene"
        tools:context=".MainActivity">

    <TextView
            android:id="@+id/left_to_right_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Left to right"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

    <TextView
            android:id="@+id/top_to_bottom_text"
            android:text="Top to bottom"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.motion.widget.MotionLayout>

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


    <Transition
            app:constraintSetStart="@id/base"
            app:constraintSetEnd="@id/bottom">
        <OnClick
                app:targetId="@id/top_to_bottom_text">

        </OnClick>

    </Transition>

    <Transition
            app:constraintSetStart="@id/base"
            app:constraintSetEnd="@id/right">
        <OnSwipe
                app:dragDirection="dragRight"
                app:touchAnchorId="@id/left_to_right_text"
                app:touchAnchorSide="right">

        </OnSwipe>

    </Transition>


    <ConstraintSet android:id="@+id/base">

        <Constraint
                android:id="@id/left_to_right_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>

        <Constraint
                android:id="@id/top_to_bottom_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/bottom">

        <Constraint
                android:id="@id/left_to_right_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>

        <Constraint
                android:id="@id/top_to_bottom_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
        />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/right">

        <Constraint
                android:id="@id/left_to_right_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>

        <Constraint
                android:id="@id/top_to_bottom_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
    </ConstraintSet>
</MotionScene>

以下是我尝试在2秒后更新一个文本视图的可见性的代码:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)

        Completable.timer(2, TimeUnit.SECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                motion_layout.getConstraintSet(R.id.base)?.let {
                    it.setVisibility(R.id.left_to_right_text, View.INVISIBLE)
                }
                motion_layout.updateState()
                // These don't work either
//                motion_layout.rebuildScene()
//                motion_layout.invalidate()
            }
    }

您可以在下面的gif中看到,我等待了2秒钟,什么也没有发生。直到我转换到新状态,然后回到原始状态才更新可见性。
2个回答

17

我找到了解决方案!

Phan Van Linh提供的解决方案对我无效(我正在使用2.0.0-beta1约束版本)

只需在您刚刚更改可见性(或其他视图属性)的视图上调用.requestLayout()即可。所以在您的示例中:

motion_layout.getConstraintSet(R.id.base)?.let {
                it.setVisibility(R.id.left_to_right_text, View.INVISIBLE)
                yourView.requestLayout() // <-- this line
            }

根据requestLayout方法的文档,它会在布局过程中遍历当前视图层次结构中的所有视图。


哦,太好了,看起来可以工作!虽然你的代码有点问题,但你是在约束集上调用requestLayout而不是视图。应该是(使用合成访问器)left_to_right_text.requestLayout()而不是it.requestLayout()。真的很想知道updateState、rebuildSchene和invalidate要做什么。感谢你的帮助! - odiggity
我也在使用2.0.0-beta1,我再次检查发现我的解决方法仍然有效,不确定为什么?无论如何,你的解决方案是更好的解决方案。谢谢你找到这个很酷的函数,我从来不知道它可以做更多的事情而不是使其无效。 - Linh

0

尝试: updateState(R.id.base, ConstraintSet)


这是您的意思吗?如果是,它也不起作用。Completable.timer(2, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe { val set = motion_layout.getConstraintSet(R.id.base)?.apply { this.setVisibility(R.id.left_to_right_text, View.INVISIBLE) } motion_layout.updateState(R.id.base, set) } - odiggity
这对我来说可行,但有点像是一个hack,我认为LionisIAm的答案更好。不过还是谢谢你的尝试! - odiggity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接