15

我有Fragment一个RecyclerViewMotionLayout. 在回收站视图之上,我有一个可以折叠和展开的视图,所有这些都在我的运动场景中完成。它由单击触发以及响应拖动回收站视图。到目前为止,这一切都按预期工作。

现在问题来了:我想在我的应用程序中完全隐藏某些状态的折叠视图。但是,如果我设置视图可见性或更改其高度,当我拖动回收器视图时,它仍然会重新出现。

那么是否可以完全禁用 MotionLayout(锁定约束),直到我再次启用它。禁用阻力识别器也是一个可行的解决方案。

现在用一些简化的 XML 来演示这种情况。

包含带有标题视图和回收器视图的运动布局的布局

<?xml version="1.0" encoding="utf-8"?>
<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/favouritesMotionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/favourites_motion_scene"
    android:animateLayoutChanges="true">

    <ImageView
        android:id="@+id/headerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        ...
        />

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        ...
    >

        <androidx.recyclerview.widget.RecyclerVieww
            android:id="@+id/favoritesList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</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"
>

    <Transition
        motion:constraintSetStart="@id/expanded"
        motion:constraintSetEnd="@id/collapsed"
        motion:duration="300">
        <OnSwipe
            motion:touchAnchorId="@id/swipeRefreshLayout"
            motion:touchAnchorSide="top"
            motion:dragDirection="dragUp" />
    </Transition>

    <ConstraintSet android:id="@+id/expanded">
        ... Constraints for expanded header ...
    </ConstraintSet>

    <ConstraintSet android:id="@+id/collapsed">
        ... ... Constraints for collapsed header ...
    </ConstraintSet>

</MotionScene>

使用约束布局版本“2.0.0-alpha3”

implementation "com.android.support.constraint:constraint-layout:2.0.0-alpha3"

所以回顾一下:我希望能够禁用运动布局,这样我就可以在不扩展标题的情况下滚动回收视图,直到我告诉它再次启用。不幸的是,它并不像favouritesMotionLayout.isEnabled = false,但这是我的想法。

4

14 回答 14

16

现在有了 ConstraintLayout beta 2,您就可以了!这是官方的做法:

motionLayout.getTransition(R.id.yourTransition).setEnable(false)

于 2019-09-24T09:24:26.730 回答
4

实际上,我设法通过为开始和结束设置场景的开始状态来使其工作。在科特林:

motionLayout.setTransition(R.id.start, R.id.start)

当我需要启用我的布局时:

motionLayout.setTransition(R.id.start, R.id.end)

无需更改您的场景 xml,在 alpha-03 中对我来说完美无缺

于 2019-05-07T10:03:11.087 回答
3

我找到了一个方便的解决方案来暂时禁用运动布局转换。将此设置为 xml 中的 MotionLayout:

app:interactionEnabled="false"

该解决方案的优点是直接在 xml 文件中使用它,这使您可以选择连接到数据绑定

app:interactionEnabled="@{viewModel.shouldInteractionBeActive}"

它开箱即用,无需任何额外的绑定适配器。这是在约束布局中添加的:2.1.0-beta01。

于 2020-04-09T13:05:55.593 回答
3

最近我一直在研究 MotionLayout,到目前为止,我发现禁用 Motionlayout 的技巧如下所示。

layoutContainer.setTransitionListener(object: MotionLayout.TransitionListener {
        override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {}
        override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {}
        override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {}
        override fun onTransitionChange(p0: MotionLayout?, startedScene: Int, endScene: Int, p3: Float) {
            when(currentFragmentTag) {
                TAG_DEFAULTBACKGROUND ->  {
                    if( startedScene==R.id.halfExpanded ) {
                        layoutContainer.transitionToState(startedScene)
                    }
                }
            }
        }
    })

所以基本上,我告诉 MotionLayout 回到某些情况。我觉得onTransitionTriggeronTransitionStarted应该包含停止功能,但在那些时刻它不会听。

onTransitionChange是它实际开始移动的地方。我想你会反之亦然地理解这个技巧。

快乐编码!

于 2019-04-06T07:45:58.170 回答
2

请注意,从最新的 beta (beta2) 开始,可以禁用转换: https ://androidstudio.googleblog.com/2019/06/constraintlayout-200-beta-2.html

Kotlin 中的示例用法:

(view as? MotionLayout)?.getTransition(R.id.swipe_transition)?.setEnable(false)
于 2019-07-02T18:39:22.383 回答
1

我正在使用androidx.constraintlayout:constraintlayout:2.0.0-beta4motionLayout.getTransition(R.id.yourTransition).setEnable(false)不适合我,但要完全禁用运动布局,例如在我的情况下,我需要在特殊情况下隐藏视图,但这个视图涉及动画。所以cardMotionLayout.loadLayoutDescription(0)完全禁用 MotionLayout,并再次启用我正在使用cardMotionLayout.loadLayoutDescription(R.xml.fragment_buy_card_step_one_scene)

于 2020-03-18T13:16:17.800 回答
0

如果您想在用户操作完成后禁用转换。只需设置 motionLayout.transitionToState(0)。您可能希望在转换完成回调中执行此操作。

检查以下代码是否适合您。

motionLayout.setTransitionListener(object : 
MotionLayout.TransitionListener {
        override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {

        }

        override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {

        }

        override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
        }

        override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {
            (motionLayout as MotionLayout).transitionToState(0)
        }

    })
于 2019-07-29T07:55:56.117 回答
0

禁用 MotionLayout 动画转换的最简单方法是在 MotionLayout 上设置属性app:applyMotionScene="false"

属性applyMotionScene是布尔格式,用于启用/禁用 MotionLayout 中的过渡。

于 2021-11-25T15:36:42.867 回答
0

LPirro接受的答案对我不起作用,我现在正在使用 beta3。相反,我根据我的要求更改了 layoutDescription :

public void enableTransition(boolean enable) {
    if (enable) loadLayoutDescription(R.xml.scene);
    else loadLayoutDescription(0);
}
于 2019-12-13T11:29:31.547 回答
0

因此,似乎有一种方法可以破解您的状态以禁用运动转换。必须在 xml 文件中的上述过渡之后添加。我添加了另一个具有相同开始和结束状态的转换。在你的情况下:

<Transition
        motion:constraintSetStart="@id/collapsed"
        motion:constraintSetEnd="@id/collapsed"
        motion:duration="0">

在 java/kotlin 中

motion_layout.setTransition(R.id.collapsed, R.id.collapsed)
于 2019-05-03T00:57:21.737 回答
0

是的,首先有可能

motionLayout.getTransition(R.id.yourTransition).setEnable(false)

现在用Transistion什么都没有代替它

motionLayout.setTransition(R.id.your_second_Transistion);
于 2021-04-23T11:50:13.623 回答
0

此时,似乎无法禁用 MotionLayout 中的动作。我希望这将在未来的版本中添加。为了解决我的用例,我使用了一些肮脏的技巧:我删除了构成标题的视图。

favouritesMotionLayout.removeView(headerView)

布局没问题,视图消失了,动作没有被触发。为了取回视图,我只是重新填充了整个布局。(另一种方法是以编程方式再次添加视图及其约束)。

我意识到这不是最漂亮的解决方案,我目前正在寻找在没有运动布局的情况下解决整个用例的方法。这很不幸,因为它对我多达 90% 的用例都非常有用。

于 2019-03-18T09:13:13.253 回答
0

好吧,我必须这样做,我尝试了 beta1 和 beta2 库,但无法禁用motionlayout,最后我这样做是为了在我的列表为空时禁用motionlayout动画:-

解决方案

// this fix the transition but other parts of layout will still able to trigger transition somehow to R.id.end!!
motionLayout.setTransition(R.id.start, R.id.start);
// disable all other views touch handling except view clicks.
motionLayout.findViewById(R.id.view_ids).setOnTouchListener(
          (v, event) -> event.getActionMasked() != MotionEvent.ACTION_UP);
motionLayout.findViewById(R.id.view_ids).setOnTouchListener(
          (v, event) -> event.getActionMasked() != MotionEvent.ACTION_UP);
     .... disable all the views touch handling cause they can trigger the motion layout animation!

// And then finally has to disable touch handling of motionlayout itself to avoid the space exposed by motionlayout due to padding or margin which can trigger the transition!
motionLayout.setOnTouchListener(
          (v, event) -> event.getActionMasked() != MotionEvent.ACTION_UP);

简而言之,我们需要setTransition为 start 和 end 设置 start id。但我观察到这还不够。由于以某种方式motionlayout禁用了触摸处理,recylerview但所有其他部分都motionlayout可以触发转换,所以我需要禁用所有其他视图的触摸处理,让它们只处理点击事件,然后最后也必须这样做motionlayout。导致motionlayout处理的视图之间的空间,因此当您触摸motionlayout所在的那些部分时,它将触发过渡。所以也需要禁用它的触摸处理。

最后它与这个解决方案一起工作!希望这个答案对某人有所帮助!:) 请享用!

于 2019-10-03T07:49:54.430 回答
0

这个对我有用:

  if (list.isNullOrEmpty()) {
                    //disable
                    motionLayout.apply {
                        setTransition(R.id.expanded, R.id.expanded)
                        setTransitionDuration(0)
                    }
                } else {
                   //enable
                    motionLayout.apply {
                        setTransition(R.id.expanded, R.id.collapsed)
                        setTransitionDuration(200)
                    }
                }





 p.s.: 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
于 2019-06-23T21:37:59.337 回答