Android Animating Constraint Layouts

yen*_*rah 5 android android-animation android-constraintlayout

我想动画两个ConstraintLayouts- 一个是另一个的孩子.

我知道动画只适用于一个直接的孩子ConstraintLayout,所以这是我的布局:

<android.support.constraint.ConstraintLayout 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/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.constraint.ConstraintLayout
        android:id="@+id/cl"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#393939"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:visibility="visible">

        <TextView
            android:id="@+id/textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Move me!"
            android:textColor="#fff"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.8" />
    </android.support.constraint.ConstraintLayout>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Animate" />
</android.support.constraint.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)

其中有一个ConstraintLayout根布局,一个内部ConstraintLayout有一个背景颜色和一个TextView.内部布局设置gone在开头.

我想淡入内部ConstraintLayout(设置其可见性View.VISIBLE)并向上移动TextView(将其vertical Bias设置为较低的数字).既然不能动画内儿童的观点,我创建4个约束集- csA用于内部的可见性动画ConstraintLayout,并csB为动漫移动TextView向上.

class MainActivity : AppCompatActivity() {
    val csA1 = ConstraintSet()
    val csA2 = ConstraintSet()

    val csB1 = ConstraintSet()
    val csB2 = ConstraintSet()

    lateinit var btn: Button
    lateinit var cl: ConstraintLayout
    lateinit var root: ConstraintLayout

    var switch = false


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

        root = findViewById(R.id.root_layout)
        val tv: TextView = findViewById(R.id.textview)
        cl = findViewById(R.id.cl)
        btn = findViewById(R.id.button)

        btn.setOnClickListener { toggle() }

        csA1.clone(root)
        csA2.clone(csA1)
        csA2.setVisibility(R.id.cl, View.VISIBLE)

        csB1.clone(cl)
        csB2.clone(csB1)
        csB2.setVerticalBias(R.id.textview, 0.3f)

    }

    fun toggle() {
        TransitionManager.beginDelayedTransition(root)
        val cs = if (!switch) csA2 else csA1
        cs.applyTo(root)
        val vsB = if (!switch) csB2 else csB1

        TransitionManager.beginDelayedTransition(cl)
        vsB.applyTo(cl)

        switch = !switch
        btn.text = "switch: $switch"
    }
}
Run Code Online (Sandbox Code Playgroud)

按下第一个按钮可能会起作用 - 但在第二次按下时,布局不会被隐藏,并且视图保持原样.文本被剪切到第一个字母,下一次单击显示全文.当触发器设置为从truefalse,背景会在非常短的时间内闪烁为白色,然后再次变为灰色.

该项目没有其他任何内容.如果我禁用其中一个动画,另一个正在运行没有任何问题.

我尝试过的:

  • vsB通过处理程序延迟 postDelayed,以及startDelay使用duration可见性动画设置自定义转换.
   
    Handler().postDelayed({
        TransitionManager.beginDelayedTransition(cl)
        vsB.applyTo(cl)
    }, 450)
Run Code Online (Sandbox Code Playgroud)
  • 使用处理程序和延迟450 ms(我没有测试这个的最小限制) - 动画确实有效.它没有滞后,每次按下按钮时布局都会正确显示和隐藏,文本视图会向上移动.但这不是我的要求.我需要同时动画它们,甚至更好:向上运动延迟50ms.

  • 使用处理程序和延迟时1 ms,首次按下时显示布局,TextView它已经处于最终位置(无移动).

  • 使用a进行自定义转换startDelay,其响应类似于没有任何内容的版本:TextView.text剪切到第一个字母,背景闪烁为白色并返回灰色.转换似乎没有任何影响,甚至没有更大的startDelay(duration + 200例如).

   
    fun toggle() {
        val duration = 200L
        val transitionA = AutoTransition()
        transitionA.duration = duration

        val transitionB = AutoTransition()
        transitionB.startDelay = duration

        TransitionManager.beginDelayedTransition(root, transitionA)
        val cs = if (!switch) csA2 else csA1
        cs.applyTo(root)

        val vsB = if (!switch) csB2 else csB1

        TransitionManager.beginDelayedTransition(cl,transitionB)
        vsB.applyTo(cl)

        switch = !switch
        btn.text = "switch: $switch"
    }
Run Code Online (Sandbox Code Playgroud)

我在API 27上的模拟器和API 24上的Samsung S6上测试了这个.其他技术信息:

   
    compileSdkVersion 27

    minSdkVersion 21
    targetSdkVersion 27

    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'


    Android Studio Version 3.1.2
    Android SDK Tools 26.1.1 
Run Code Online (Sandbox Code Playgroud)

两个同步动画ConstraintLayouts甚至可能吗?

小智 2

由于我仍然无法发表评论(没有足够的代表),因此我将其写在这里,但请像评论一样阅读它。
您对 ConstraintSets 的看法是错误的。
如果您只想设置一些内容可见并将其动画到另一个位置,则需要创建两个 .xml。它们内部需要具有相同的视图(无论是否可见),然后通过 TransitionManager 和 ConstraintSets 应用它们。
没有代码的简单示例:

您有一个 ConstraintLayout xml,其中包含一个 ImageView。在第一个 xml 中,它设置为布局的顶部,在第二个 xml 中,您将其设置为底部。当您现在克隆这些布局并将一个布局应用到另一个布局时(可能单击按钮),它将为 ImageView 从上到下设置动画。

再看一下官方文档,然后尝试一下。如果你理解一次,其实很容易。如果您还有其他问题或希望我给您提供更好的示例,请尽管询问。