0

我有以下活动和布局:

import android.os.Bundle
import android.view.Gravity
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.transition.Slide
import androidx.transition.TransitionManager
import com.tests.playground.R


class ConstraintLayoutTransitionActivity : AppCompatActivity() {

    private val rootView: ConstraintLayout by lazy { findViewById(R.id.root) }
    private val bottomBlueView: View by lazy { findViewById(R.id.bottomBlue) }
    private val switchButton: View by lazy { findViewById(R.id.switchButton) }
    private var isBottomBlueViewShowing = true

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_constraint_layout_transition)

        switchButton.setOnClickListener(::onSwitchButtonClicked)
    }

    @Synchronized
    private fun onSwitchButtonClicked(view: View) {
        isBottomBlueViewShowing = !isBottomBlueViewShowing

        val constraintSet = ConstraintSet()
        constraintSet.clone(rootView)

        val transition = Slide()
        transition.duration = 1000L

        if (isBottomBlueViewShowing) {
            constraintSet.setVisibility(bottomBlueView.id, View.VISIBLE)
            transition.slideEdge = Gravity.BOTTOM
        } else {
            constraintSet.setVisibility(bottomBlueView.id, View.GONE)
            transition.slideEdge = Gravity.BOTTOM
        }

        TransitionManager.beginDelayedTransition(rootView, transition)
        constraintSet.applyTo(rootView)
    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/topRed"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#F00"
        app:layout_constraintBottom_toTopOf="@+id/bottomBlue"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/switchButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:text="Switch"
        app:layout_constraintBottom_toBottomOf="@+id/topRed"
        app:layout_constraintEnd_toEndOf="@+id/topRed"
        app:layout_constraintStart_toStartOf="@+id/topRed"
        app:layout_constraintTop_toTopOf="@+id/topRed" />

    <View
        android:id="@+id/bottomBlue"
        android:layout_width="0dp"
        android:layout_height="142dp"
        android:background="#00F"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

当我尝试显示/隐藏bottomBlue时,会发生以下情况:

轻弹

如你看到的,

  • 当我隐藏视图时,按钮直接向下而不动画(bottomBlueView 动画没问题;
  • 当我显示视图时,按钮也会直接向上而不动画。但最让我烦恼的是,在动画开始之前会显示一个白色区域并一直停留在那里直到结束。

有没有办法解决这些动画问题?我已经尝试了很多方法(使用ConstraintSetand Animation),但它们都没有按预期工作。

4

1 回答 1

3

您可以AutoTransition用于过渡。

TransitionManager.beginDelayedTransition(rootView, AutoTransition())
    

结果将是这样的:

自动过渡

AutoTransition使用淡入淡出过渡来改变蓝色区域的可见性。如果您需要蓝色区域来滑动,您应该提供自定义过渡。它应该是ChangeBounds红色区域和蓝色按钮的Slide过渡以及蓝色区域的过渡:

private val topRed: View by lazy { findViewById(R.id.topRed) }
  
private fun onSwitchButtonClicked(view: View) {
        isBottomBlueViewShowing = !isBottomBlueViewShowing

        val transitionSet = TransitionSet()
        transitionSet.ordering = TransitionSet.ORDERING_TOGETHER

        //blue btn
        val blueBtnTransition = Slide(Gravity.BOTTOM)
        blueBtnTransition.addTarget(bottomBlueView)

        //red area + switch btn
        val topRedTransition = ChangeBounds()
        topRedTransition.addTarget(topRed)
        topRedTransition.addTarget(switchButton)

        transitionSet.addTransition(blueBtnTransition)
        transitionSet.addTransition(topRedTransition)

        val blueBtnVisibility = if (isBottomBlueViewShowing) {
            View.VISIBLE
        } else {
            View.GONE
        }

        val constraintSet = ConstraintSet()
        constraintSet.clone(rootView)
        constraintSet.setVisibility(bottomBlueView.id, blueBtnVisibility)

        TransitionManager.beginDelayedTransition(rootView, transitionSet)
        constraintSet.applyTo(rootView)
    }

这是结果:

custom_transition

如您所见,动画时红色和蓝色区域之间仍有白色区域。您可以通过向转换添加延迟来解决它:

    blueBtnTransition.startDelay = if (isBottomBlueViewShowing) 0 else 100
    topRedTransition.startDelay = if (isBottomBlueViewShowing) 100 else 0

这是结果。恕我直言,延迟看起来好多了:

with_delays

于 2021-03-09T14:50:13.673 回答