image: new cover selection animation
This commit is contained in:
parent
59fd4b5e18
commit
89110c2798
2 changed files with 50 additions and 51 deletions
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.image
|
package org.oxycblt.auxio.image
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
import android.animation.Animator
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
|
@ -56,12 +56,12 @@ import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Playlist
|
import org.oxycblt.auxio.music.Playlist
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
import org.oxycblt.auxio.ui.MaterialFader
|
||||||
import org.oxycblt.auxio.ui.UISettings
|
import org.oxycblt.auxio.ui.UISettings
|
||||||
import org.oxycblt.auxio.util.getAttrColorCompat
|
import org.oxycblt.auxio.util.getAttrColorCompat
|
||||||
import org.oxycblt.auxio.util.getColorCompat
|
import org.oxycblt.auxio.util.getColorCompat
|
||||||
import org.oxycblt.auxio.util.getDimenPixels
|
import org.oxycblt.auxio.util.getDimenPixels
|
||||||
import org.oxycblt.auxio.util.getDrawableCompat
|
import org.oxycblt.auxio.util.getDrawableCompat
|
||||||
import org.oxycblt.auxio.util.getInteger
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auxio's extension of [ImageView] that enables cover art loading and playing indicator and
|
* Auxio's extension of [ImageView] that enables cover art loading and playing indicator and
|
||||||
|
@ -93,7 +93,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
private val selectionBadge: ImageView?
|
private val selectionBadge: ImageView?
|
||||||
private val iconSize: Int?
|
private val iconSize: Int?
|
||||||
|
|
||||||
private var fadeAnimator: ValueAnimator? = null
|
private val fader = MaterialFader.forSmallComponent(context)
|
||||||
|
private var fadeAnimator: Animator? = null
|
||||||
private val indicatorMatrix = Matrix()
|
private val indicatorMatrix = Matrix()
|
||||||
private val indicatorMatrixSrc = RectF()
|
private val indicatorMatrixSrc = RectF()
|
||||||
private val indicatorMatrixDst = RectF()
|
private val indicatorMatrixDst = RectF()
|
||||||
|
@ -294,43 +295,10 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invalidateSelectionIndicatorAlpha(selectionBadge: ImageView) {
|
private fun invalidateSelectionIndicatorAlpha(selectionBadge: ImageView) {
|
||||||
// Set up a target transition for the selection indicator.
|
fadeAnimator?.cancel()
|
||||||
val targetAlpha: Float
|
|
||||||
val targetDuration: Long
|
|
||||||
|
|
||||||
if (isActivated) {
|
|
||||||
// View is "activated" (i.e marked as selected), so show the selection indicator.
|
|
||||||
targetAlpha = 1f
|
|
||||||
targetDuration = context.getInteger(R.integer.anim_fade_enter_duration).toLong()
|
|
||||||
} else {
|
|
||||||
// View is not "activated", hide the selection indicator.
|
|
||||||
targetAlpha = 0f
|
|
||||||
targetDuration = context.getInteger(R.integer.anim_fade_exit_duration).toLong()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectionBadge.alpha == targetAlpha) {
|
|
||||||
// Nothing to do.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLaidOut) {
|
|
||||||
// Not laid out, initialize it without animation before drawing.
|
|
||||||
selectionBadge.alpha = targetAlpha
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fadeAnimator != null) {
|
|
||||||
// Cancel any previous animation.
|
|
||||||
fadeAnimator?.cancel()
|
|
||||||
fadeAnimator = null
|
|
||||||
}
|
|
||||||
|
|
||||||
fadeAnimator =
|
fadeAnimator =
|
||||||
ValueAnimator.ofFloat(selectionBadge.alpha, targetAlpha).apply {
|
(if (isActivated) fader.fadeIn(selectionBadge) else fader.fadeOut(selectionBadge))
|
||||||
duration = targetDuration
|
.also { it.start() }
|
||||||
addUpdateListener { selectionBadge.alpha = it.animatedValue as Float }
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -97,12 +97,21 @@ class MaterialCornerAnim(context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MaterialFader private constructor(context: Context, private val scale: Float) {
|
class MaterialFader
|
||||||
private val alphaOutConfig =
|
private constructor(
|
||||||
AnimConfig.of(context, AnimConfig.EMPHASIZED_ACCELERATE, AnimConfig.SHORT3)
|
context: Context,
|
||||||
private val scaleOutConfig =
|
private val scale: Float,
|
||||||
AnimConfig.of(context, AnimConfig.EMPHASIZED_ACCELERATE, AnimConfig.MEDIUM1)
|
@AttrRes outInterpolator: Int,
|
||||||
private val inConfig = AnimConfig.of(context, AnimConfig.EMPHASIZED, AnimConfig.LONG2)
|
alphaOutDuration: Pair<Int, Int>,
|
||||||
|
scaleOutDuration: Pair<Int, Int>,
|
||||||
|
inInterpolator: Int,
|
||||||
|
alphaInDuration: Pair<Int, Int>,
|
||||||
|
scaleInDuration: Pair<Int, Int>
|
||||||
|
) {
|
||||||
|
private val alphaOutConfig = AnimConfig.of(context, outInterpolator, alphaOutDuration)
|
||||||
|
private val scaleOutConfig = AnimConfig.of(context, outInterpolator, scaleOutDuration)
|
||||||
|
private val alphaInConfig = AnimConfig.of(context, inInterpolator, alphaInDuration)
|
||||||
|
private val scaleInConfig = AnimConfig.of(context, inInterpolator, scaleInDuration)
|
||||||
|
|
||||||
fun jumpToFadeOut(view: View) {
|
fun jumpToFadeOut(view: View) {
|
||||||
view.apply {
|
view.apply {
|
||||||
|
@ -128,7 +137,11 @@ class MaterialFader private constructor(context: Context, private val scale: Flo
|
||||||
return AnimatorSet()
|
return AnimatorSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
val alphaAnimator = alphaOutConfig.genericFloat(view.alpha, 0f) { view.alpha = it }
|
val alphaAnimator =
|
||||||
|
alphaOutConfig.genericFloat(view.alpha, 0f) {
|
||||||
|
view.alpha = it
|
||||||
|
view.isInvisible = view.alpha == 0f
|
||||||
|
}
|
||||||
val scaleXAnimator = scaleOutConfig.genericFloat(view.scaleX, scale) { view.scaleX = it }
|
val scaleXAnimator = scaleOutConfig.genericFloat(view.scaleX, scale) { view.scaleX = it }
|
||||||
val scaleYAnimator = scaleOutConfig.genericFloat(view.scaleY, scale) { view.scaleY = it }
|
val scaleYAnimator = scaleOutConfig.genericFloat(view.scaleY, scale) { view.scaleY = it }
|
||||||
return AnimatorSet().apply { playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator) }
|
return AnimatorSet().apply { playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator) }
|
||||||
|
@ -140,19 +153,37 @@ class MaterialFader private constructor(context: Context, private val scale: Flo
|
||||||
return AnimatorSet()
|
return AnimatorSet()
|
||||||
}
|
}
|
||||||
val alphaAnimator =
|
val alphaAnimator =
|
||||||
inConfig.genericFloat(view.alpha, 1f) {
|
alphaInConfig.genericFloat(view.alpha, 1f) {
|
||||||
view.alpha = it
|
view.alpha = it
|
||||||
view.isInvisible = view.alpha == 0f
|
view.isInvisible = view.alpha == 0f
|
||||||
}
|
}
|
||||||
val scaleXAnimator = inConfig.genericFloat(view.scaleX, 1.0f) { view.scaleX = it }
|
val scaleXAnimator = scaleInConfig.genericFloat(view.scaleX, 1.0f) { view.scaleX = it }
|
||||||
val scaleYAnimator = inConfig.genericFloat(view.scaleY, 1.0f) { view.scaleY = it }
|
val scaleYAnimator = scaleInConfig.genericFloat(view.scaleY, 1.0f) { view.scaleY = it }
|
||||||
return AnimatorSet().apply { playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator) }
|
return AnimatorSet().apply { playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator) }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun forSmallComponent(context: Context) = MaterialFader(context, 0.4f)
|
fun forSmallComponent(context: Context) =
|
||||||
|
MaterialFader(
|
||||||
|
context,
|
||||||
|
0.6f,
|
||||||
|
AnimConfig.EMPHASIZED_ACCELERATE,
|
||||||
|
AnimConfig.SHORT1,
|
||||||
|
AnimConfig.SHORT3,
|
||||||
|
AnimConfig.EMPHASIZED_DECELERATE,
|
||||||
|
AnimConfig.SHORT1,
|
||||||
|
AnimConfig.MEDIUM3)
|
||||||
|
|
||||||
fun forLargeComponent(context: Context) = MaterialFader(context, 0.9f)
|
fun forLargeComponent(context: Context) =
|
||||||
|
MaterialFader(
|
||||||
|
context,
|
||||||
|
0.9f,
|
||||||
|
AnimConfig.EMPHASIZED_ACCELERATE,
|
||||||
|
AnimConfig.SHORT3,
|
||||||
|
AnimConfig.MEDIUM1,
|
||||||
|
AnimConfig.EMPHASIZED,
|
||||||
|
AnimConfig.LONG2,
|
||||||
|
AnimConfig.LONG2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue