问题
I want to change image in fab button during transition, but i haven't found how to do it with xml because CustomAttribute tag supports only drawable colors as values. My solution is to set TransitionAdapter to MotionLayout and change drawable in onTransitionChange function.
motionLayout.setTransitionListener(object : TransitionAdapter() {
var fromStart = true
var wasChanged = false
override fun onTransitionChange(
motionLayout: MotionLayout?,
startId: Int,
endId: Int,
progress: Float
) {
if (!wasChanged) {
if (fromStart && progress >= 0.5f) {
fab.setImageResource(R.drawable.ic_done_black_24dp)
wasChanged = true
}
if (!fromStart && progress <= 0.5f) {
fab.setImageResource(R.drawable.ic_add_black_24dp)
wasChanged = true
}
}
}
override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
wasChanged = false
fromStart = !fromStart
}
})
But in this case image changes immediately. Is there any way to make the transition smooth like in regular transition in MotionLayout?
回答1:
There is a great way to animate the change between two images in MotionLayout. However, it may be a little tricky with the Fab interaction. As shown in this blog post, you can use an ImageFilterView and set the source and alternate source, then crossfade between them. Grabbing code directly from the blog post linked above, here's an example of what an ImageFilterView looks like in your MotionLayout
<android.support.constraint.utils.ImageFilterView
android:id="@+id/image"
android:background="@color/colorAccent"
android:src="@drawable/roard"
app:altSrc="@drawable/hoford"
android:layout_width="64dp"
android:layout_height="64dp"/>
Where android:src
is your first image that you want and the app:altSrc
is the second image that you want to crossfade to.
Below, also grabbed directly from the blog post, is what the constraints will look like in your motionScene.
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="0" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="1" />
</Constraint>
</ConstraintSet>
Where you set the crossfade value as a custom attribute. Not sure how this will play with the Fab but this is the best way I know how to animate between two images.
回答2:
Try using
TransitionDrawable
to animate and changeFloatingActionButton
drawable smoothly.
private fun setMotionListener() {
val transitionDrawable = TransitionDrawable(
arrayOf(
bitmapDrawableFromVector(this, R.drawable.ic_add),
bitmapDrawableFromVector(this, R.drawable.ic_remove)
)
)
transitionDrawable.isCrossFadeEnabled = true
credits.setImageDrawable(transitionDrawable)
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) {
transitionDrawable.apply {
if (p0?.currentState == p0?.endState)
startTransition(0)
else
reverseTransition(200)
}
}
})
}
Be aware that
VectorDrawables
won't be cross-faded in theTransitionDrawable
, You'll need to convert them intoBitmapDrawables
first. See the below code -
private fun bitmapDrawableFromVector(
context: Context,
drawableId: Int
) = BitmapDrawable(context.resources, getBitmapFromVectorDrawable(context, drawableId))
private fun getBitmapFromVectorDrawable(context: Context, drawableId: Int): Bitmap? {
val drawable = ContextCompat.getDrawable(context, drawableId)
val bitmap = Bitmap.createBitmap(
drawable!!.intrinsicWidth,
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
Thanks.
来源:https://stackoverflow.com/questions/60532150/how-to-smoothly-change-drawable-resource-during-motionlayout-transition