ui: use material transitions on some shapes
These look a lot better than the old ones.
This commit is contained in:
parent
e809b2875e
commit
f742aa7592
3 changed files with 83 additions and 27 deletions
|
@ -31,15 +31,17 @@ import android.view.WindowInsets
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
|
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.R as MR
|
||||||
|
import com.google.android.material.motion.MotionUtils
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.list.recycler.AuxioRecyclerView
|
import org.oxycblt.auxio.list.recycler.AuxioRecyclerView
|
||||||
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
|
|
||||||
import org.oxycblt.auxio.util.isRtl
|
import org.oxycblt.auxio.util.isRtl
|
||||||
import org.oxycblt.auxio.util.isUnder
|
import org.oxycblt.auxio.util.isUnder
|
||||||
import org.oxycblt.auxio.util.systemBarInsetsCompat
|
import org.oxycblt.auxio.util.systemBarInsetsCompat
|
||||||
|
@ -79,10 +81,28 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
// Thumb
|
// Thumb
|
||||||
private val thumbView =
|
private val thumbView =
|
||||||
View(context).apply {
|
View(context).apply {
|
||||||
alpha = 0f
|
scaleX = 0f
|
||||||
background = context.getDrawableCompat(R.drawable.ui_scroll_thumb)
|
background = context.getDrawableCompat(R.drawable.ui_scroll_thumb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val thumbEnterInterpolator =
|
||||||
|
MotionUtils.resolveThemeInterpolator(
|
||||||
|
context,
|
||||||
|
MR.attr.motionEasingEmphasizedDecelerateInterpolator,
|
||||||
|
FastOutSlowInInterpolator())
|
||||||
|
|
||||||
|
private val thumbEnterDuration =
|
||||||
|
MotionUtils.resolveThemeDuration(context, MR.attr.motionDurationShort4, 300)
|
||||||
|
|
||||||
|
private val thumbExitInterpolator =
|
||||||
|
MotionUtils.resolveThemeInterpolator(
|
||||||
|
context,
|
||||||
|
MR.attr.motionEasingEmphasizedAccelerateInterpolator,
|
||||||
|
FastOutSlowInInterpolator())
|
||||||
|
|
||||||
|
private val thumbExitDuration =
|
||||||
|
MotionUtils.resolveThemeDuration(context, MR.attr.motionDurationShort2, 100)
|
||||||
|
|
||||||
private val thumbWidth = thumbView.background.intrinsicWidth
|
private val thumbWidth = thumbView.background.intrinsicWidth
|
||||||
private val thumbHeight = thumbView.background.intrinsicHeight
|
private val thumbHeight = thumbView.background.intrinsicHeight
|
||||||
private val thumbPadding = Rect(0, 0, 0, 0)
|
private val thumbPadding = Rect(0, 0, 0, 0)
|
||||||
|
@ -98,6 +118,9 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
// Popup
|
// Popup
|
||||||
private val popupView =
|
private val popupView =
|
||||||
FastScrollPopupView(context).apply {
|
FastScrollPopupView(context).apply {
|
||||||
|
scaleX = 0f
|
||||||
|
scaleY = 0f
|
||||||
|
alpha = 0f
|
||||||
layoutParams =
|
layoutParams =
|
||||||
FrameLayout.LayoutParams(
|
FrameLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
@ -107,6 +130,24 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val popupEnterInterpolator =
|
||||||
|
MotionUtils.resolveThemeInterpolator(
|
||||||
|
context,
|
||||||
|
MR.attr.motionEasingEmphasizedDecelerateInterpolator,
|
||||||
|
FastOutSlowInInterpolator())
|
||||||
|
|
||||||
|
private val popupEnterDuration =
|
||||||
|
MotionUtils.resolveThemeDuration(context, MR.attr.motionDurationMedium1, 300)
|
||||||
|
|
||||||
|
private val popupExitInterpolator =
|
||||||
|
MotionUtils.resolveThemeInterpolator(
|
||||||
|
context,
|
||||||
|
MR.attr.motionEasingEmphasizedAccelerateInterpolator,
|
||||||
|
FastOutSlowInInterpolator())
|
||||||
|
|
||||||
|
private val popupExitDuration =
|
||||||
|
MotionUtils.resolveThemeDuration(context, MR.attr.motionDurationShort2, 100)
|
||||||
|
|
||||||
private var showingPopup = false
|
private var showingPopup = false
|
||||||
|
|
||||||
// Touch
|
// Touch
|
||||||
|
@ -417,7 +458,12 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
showingThumb = true
|
showingThumb = true
|
||||||
animateViewIn(thumbView)
|
thumbView
|
||||||
|
.animate()
|
||||||
|
.scaleX(1f)
|
||||||
|
.setInterpolator(thumbEnterInterpolator)
|
||||||
|
.setDuration(thumbEnterDuration.toLong())
|
||||||
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideScrollbar() {
|
private fun hideScrollbar() {
|
||||||
|
@ -426,7 +472,12 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
showingThumb = false
|
showingThumb = false
|
||||||
animateViewOut(thumbView)
|
thumbView
|
||||||
|
.animate()
|
||||||
|
.scaleX(0f)
|
||||||
|
.setInterpolator(thumbExitInterpolator)
|
||||||
|
.setDuration(thumbExitDuration.toLong())
|
||||||
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showPopup() {
|
private fun showPopup() {
|
||||||
|
@ -434,8 +485,18 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popupView.scaleX = 0f
|
||||||
|
popupView.scaleY = 0f
|
||||||
|
|
||||||
|
popupView.alpha = 1f
|
||||||
showingPopup = true
|
showingPopup = true
|
||||||
animateViewIn(popupView)
|
popupView
|
||||||
|
.animate()
|
||||||
|
.scaleX(1f)
|
||||||
|
.scaleY(1f)
|
||||||
|
.setInterpolator(popupEnterInterpolator)
|
||||||
|
.setDuration(popupEnterDuration.toLong())
|
||||||
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hidePopup() {
|
private fun hidePopup() {
|
||||||
|
@ -444,22 +505,13 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
showingPopup = false
|
showingPopup = false
|
||||||
animateViewOut(popupView)
|
popupView
|
||||||
}
|
|
||||||
|
|
||||||
private fun animateViewIn(view: View) {
|
|
||||||
view
|
|
||||||
.animate()
|
|
||||||
.alpha(1f)
|
|
||||||
.setDuration(context.getInteger(R.integer.anim_fade_enter_duration).toLong())
|
|
||||||
.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun animateViewOut(view: View) {
|
|
||||||
view
|
|
||||||
.animate()
|
.animate()
|
||||||
.alpha(0f)
|
.alpha(0f)
|
||||||
.setDuration(context.getInteger(R.integer.anim_fade_exit_duration).toLong())
|
.scaleX(0.75f)
|
||||||
|
.scaleY(0.75f)
|
||||||
|
.setInterpolator(popupExitInterpolator)
|
||||||
|
.setDuration(popupExitDuration.toLong())
|
||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ package org.oxycblt.auxio.playback.service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.media.audiofx.AudioEffect
|
import android.media.audiofx.AudioEffect
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.media3.common.AudioAttributes
|
import androidx.media3.common.AudioAttributes
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
|
|
|
@ -21,11 +21,11 @@ package org.oxycblt.auxio.playback.ui
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.animation.AnimationUtils
|
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||||
|
import com.google.android.material.R as MR
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import org.oxycblt.auxio.R
|
import com.google.android.material.motion.MotionUtils
|
||||||
import org.oxycblt.auxio.ui.RippleFixMaterialButton
|
import org.oxycblt.auxio.ui.RippleFixMaterialButton
|
||||||
import org.oxycblt.auxio.util.getInteger
|
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,6 +48,13 @@ class AnimatedMaterialButton : RippleFixMaterialButton {
|
||||||
private var currentCornerRadiusRatio = 0f
|
private var currentCornerRadiusRatio = 0f
|
||||||
private var animator: ValueAnimator? = null
|
private var animator: ValueAnimator? = null
|
||||||
|
|
||||||
|
private val matInterpolator =
|
||||||
|
MotionUtils.resolveThemeInterpolator(
|
||||||
|
context, MR.attr.motionEasingStandardInterpolator, FastOutSlowInInterpolator())
|
||||||
|
|
||||||
|
private val matDuration =
|
||||||
|
MotionUtils.resolveThemeDuration(context, MR.attr.motionDurationMedium2, 300)
|
||||||
|
|
||||||
override fun setActivated(activated: Boolean) {
|
override fun setActivated(activated: Boolean) {
|
||||||
super.setActivated(activated)
|
super.setActivated(activated)
|
||||||
|
|
||||||
|
@ -64,10 +71,8 @@ class AnimatedMaterialButton : RippleFixMaterialButton {
|
||||||
animator?.cancel()
|
animator?.cancel()
|
||||||
animator =
|
animator =
|
||||||
ValueAnimator.ofFloat(currentCornerRadiusRatio, targetRadius).apply {
|
ValueAnimator.ofFloat(currentCornerRadiusRatio, targetRadius).apply {
|
||||||
duration = context.getInteger(R.integer.anim_fade_enter_duration).toLong()
|
duration = matDuration.toLong()
|
||||||
interpolator =
|
interpolator = matInterpolator
|
||||||
AnimationUtils.loadInterpolator(
|
|
||||||
context, android.R.interpolator.fast_out_slow_in)
|
|
||||||
addUpdateListener { updateCornerRadiusRatio(animatedValue as Float) }
|
addUpdateListener { updateCornerRadiusRatio(animatedValue as Float) }
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue