我想给两个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
为根布局,内部包含有背景颜色和TextView
的ConstraintLayout
。一开始将内部布局设置为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
的同时动画是否可能?
ValueAnimator
来实现动画效果,效果还不错。希望能够知道这种情况是否被支持。 :) - yennsarah