安卓动画约束布局

6

我想给两个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>

一个以ConstraintLayout为根布局,内部包含有背景颜色和TextViewConstraintLayout。一开始将内部布局设置为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"
    }
}

第一次按钮按下时可能有效,但第二次按下时,布局不会被隐藏,视图保持在原地。文字被截断为第一个字母,完整文本会在下一次点击时显示。当触发器从 true 更改为 false 时,背景会短暂闪白色,然后再变成灰色。
该项目中没有其他内容。如果我禁用其中一个动画,另一个动画就能正常运行。
我尝试过:
  • 通过Handler和postDelayed 延迟 vsB 的设置以及使用具有 startDelay 的自定义转换和可见性动画的 duration
   
    Handler().postDelayed({
        TransitionManager.beginDelayedTransition(cl)
        vsB.applyTo(cl)
    }, 450)
  • 使用处理程序和延迟450毫秒(我没有测试最小限制)- 动画可以正常工作。它不会延迟,布局在每次按钮按下时都会正确显示和隐藏,并且文本视图向上移动。但这并不完全符合我的要求。我需要同时进行动画,或者更好的是:在向上移动时延迟50毫秒。

  • 使用处理程序和延迟1毫秒,第一次按下时将显示布局,TextView已经处于最终位置(没有移动)。

  • 自定义转换与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"
    }

我在API 27的模拟器和API 24的三星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 

两个ConstraintLayouts的同时动画是否可能?


我提交了一个错误报告:https://issuetracker.google.com/issues/109827623 我目前使用ValueAnimator来实现动画效果,效果还不错。希望能够知道这种情况是否被支持。 :) - yennsarah
1个回答

2

因为我还不能评论(声望不够),所以我会在这里写,但请把它看作是一条评论。
你对ConstraintSets的理解有误。
如果你只想设置一些内容可见并将其动画移动到另一个位置,你需要创建两个.xml文件。它们需要具有相同的视图(无论是否可见),然后通过TransitionManager和ConstraintSets应用它们。
以下是一个简单的示例,没有代码:

你有一个ConstraintLayout xml,其中包含一个ImageView。在第一个xml中,它被设置为位于布局的顶部,在第二个xml中,你将其设置为底部。当你现在克隆这些布局并将一个应用于另一个(可能是在按钮点击时),那么它将会将ImageView从顶部动画移到底部。

再次查看官方文档,并按照该方式尝试。如果你理解了一次,它实际上很容易。如果你有进一步的问题或想让我给你一个更好的示例,请随时问我。


ConstraintSets 也可以像上面那样工作 - 我可以通过我的 ConstraintSets 设置属性。即使我复制布局 - 我仍然需要同时在两个 ConstraintLayouts 上执行两个动画 - 这似乎不起作用。不幸的是,我无法更改现有的 ConstraintLayouts 嵌套。 - yennsarah
我不知道这一点,它看起来比应该的要复杂得多。如果您无法更改嵌套,并且您说它不适用于嵌套布局,则请忽略我的评论。我不知道为什么您需要嵌套,因为您给出的示例并不需要,但好吧。祝你好运! - IntersectGlasses
我创建了一个示例布局,当然没有真实项目的复杂性 - 以检查它是否是复杂布局,并更自由地测试动画。 ;) - yennsarah

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