Migrate to TransitionManager from custom animations

This commit is contained in:
Koitharu
2022-03-08 19:18:02 +02:00
parent 15c570979b
commit ccf4e4d285
5 changed files with 34 additions and 172 deletions

View File

@@ -18,6 +18,9 @@ import androidx.core.view.postDelayed
import androidx.core.view.updatePadding
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
import androidx.transition.Slide
import androidx.transition.TransitionManager
import androidx.transition.TransitionSet
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
@@ -47,8 +50,9 @@ import org.koitharu.kotatsu.reader.ui.thumbnails.PagesThumbnailsSheet
import org.koitharu.kotatsu.utils.GridTouchHelper
import org.koitharu.kotatsu.utils.ScreenOrientationHelper
import org.koitharu.kotatsu.utils.ShareHelper
import org.koitharu.kotatsu.utils.anim.Motion
import org.koitharu.kotatsu.utils.ext.*
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.hasGlobalPoint
import org.koitharu.kotatsu.utils.ext.observeWithPrevious
class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
ChaptersBottomSheet.OnChapterChangeListener,
@@ -310,13 +314,16 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
private fun setUiIsVisible(isUiVisible: Boolean) {
if (binding.appbarTop.isVisible != isUiVisible) {
val transition = TransitionSet()
.setOrdering(TransitionSet.ORDERING_TOGETHER)
.addTransition(Slide(Gravity.BOTTOM).addTarget(binding.appbarBottom))
.addTransition(Slide(Gravity.TOP).addTarget(binding.appbarTop))
TransitionManager.beginDelayedTransition(binding.root, transition)
binding.appbarTop.isVisible = isUiVisible
binding.appbarBottom.isVisible = isUiVisible
if (isUiVisible) {
binding.appbarTop.showAnimated(Motion.SlideTop)
binding.appbarBottom.showAnimated(Motion.SlideBottom)
showSystemUI()
} else {
binding.appbarTop.hideAnimated(Motion.SlideTop)
binding.appbarBottom.hideAnimated(Motion.SlideBottom)
hideSystemUI()
}
}

View File

@@ -3,13 +3,16 @@ package org.koitharu.kotatsu.reader.ui
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.Gravity
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.core.view.isVisible
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import androidx.transition.Fade
import androidx.transition.Slide
import androidx.transition.TransitionManager
import androidx.transition.TransitionSet
import com.google.android.material.textview.MaterialTextView
import org.koitharu.kotatsu.utils.anim.Duration
import org.koitharu.kotatsu.utils.anim.Motion
import org.koitharu.kotatsu.utils.ext.hideAnimated
import org.koitharu.kotatsu.utils.ext.showAnimated
class ReaderToastView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
@@ -22,7 +25,8 @@ class ReaderToastView @JvmOverloads constructor(
fun show(message: CharSequence, isLoading: Boolean) {
removeCallbacks(hideRunnable)
text = message
this.showAnimated(Motion.Toast, Duration.SHORT)
setupTransition()
isVisible = true
}
fun show(@StringRes messageId: Int, isLoading: Boolean) {
@@ -36,7 +40,8 @@ class ReaderToastView @JvmOverloads constructor(
fun hide() {
removeCallbacks(hideRunnable)
this.hideAnimated(Motion.Toast, Duration.SHORT)
setupTransition()
isVisible = false
}
override fun onDetachedFromWindow() {
@@ -44,6 +49,16 @@ class ReaderToastView @JvmOverloads constructor(
super.onDetachedFromWindow()
}
private fun setupTransition () {
val parentView = parent as? ViewGroup ?: return
val transition = TransitionSet()
.setOrdering(TransitionSet.ORDERING_TOGETHER)
.addTarget(this)
.addTransition(Slide(Gravity.BOTTOM))
.addTransition(Fade())
TransitionManager.beginDelayedTransition(parentView, transition)
}
// FIXME use it as compound drawable
private fun createProgressDrawable(): CircularProgressDrawable {
val drawable = CircularProgressDrawable(context)

View File

@@ -1,9 +0,0 @@
package org.koitharu.kotatsu.utils.anim
import androidx.annotation.IntegerRes
enum class Duration(@IntegerRes val resId: Int) {
SHORT(android.R.integer.config_shortAnimTime),
MEDIUM(android.R.integer.config_mediumAnimTime),
LONG(android.R.integer.config_longAnimTime)
}

View File

@@ -1,94 +0,0 @@
package org.koitharu.kotatsu.utils.anim
import android.view.View
import android.view.ViewPropertyAnimator
import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
import org.koitharu.kotatsu.utils.ext.measureHeight
sealed class Motion {
abstract fun reset(v: View)
abstract fun hideView(v: View)
abstract fun hide(v: View, anim: ViewPropertyAnimator)
abstract fun show(v: View, anim: ViewPropertyAnimator)
object CrossFade : Motion() {
override fun reset(v: View) {
v.alpha = 1f
}
override fun hideView(v: View) {
v.alpha = 0f
}
override fun hide(v: View, anim: ViewPropertyAnimator) {
anim.alpha(0f)
}
override fun show(v: View, anim: ViewPropertyAnimator) {
anim.alpha(1f)
}
}
object SlideBottom : Motion() {
override fun reset(v: View) {
v.translationY = 0f
}
override fun hideView(v: View) {
v.translationY = v.measureHeight().toFloat()
}
override fun hide(v: View, anim: ViewPropertyAnimator) {
anim.translationY(v.measureHeight().toFloat())
}
override fun show(v: View, anim: ViewPropertyAnimator) {
anim.translationY(0f)
}
}
object SlideTop : Motion() {
override fun reset(v: View) {
v.translationY = 0f
}
override fun hideView(v: View) {
v.translationY = -v.measureHeight().toFloat()
}
override fun hide(v: View, anim: ViewPropertyAnimator) {
anim.translationY(-v.measureHeight().toFloat())
}
override fun show(v: View, anim: ViewPropertyAnimator) {
anim.translationY(0f)
}
}
object Toast : Motion() {
override fun reset(v: View) {
v.alpha = 1f
}
override fun hideView(v: View) {
v.alpha = 0f
}
override fun hide(v: View, anim: ViewPropertyAnimator) {
anim.alpha(0f)
anim.translationY(v.measureHeight().toFloat())
anim.interpolator = AccelerateInterpolator()
}
override fun show(v: View, anim: ViewPropertyAnimator) {
anim.alpha(1f)
anim.translationY(0f)
anim.interpolator = DecelerateInterpolator()
}
}
}

View File

@@ -1,57 +0,0 @@
package org.koitharu.kotatsu.utils.ext
import android.view.View
import org.koitharu.kotatsu.utils.anim.Duration
import org.koitharu.kotatsu.utils.anim.Motion
fun View.showAnimated(
effect: Motion,
duration: Duration = Duration.MEDIUM,
onDone: (() -> Unit)? = null
) {
if (this.visibility == View.VISIBLE) {
onDone?.invoke()
return
}
this.clearAnimation()
effect.hideView(this)
this.visibility = View.VISIBLE
this.animate().also {
it.duration = context.resources.getInteger(duration.resId).toLong()
effect.show(this, it)
}.withEndAction(onDone)
.start()
}
fun View.hideAnimated(
effect: Motion,
duration: Duration = Duration.MEDIUM,
onDone: (() -> Unit)? = null
) {
if (this.visibility != View.VISIBLE) {
onDone?.invoke()
return
}
this.clearAnimation()
this.animate().also {
it.duration = context.resources.getInteger(duration.resId).toLong()
effect.hide(this, it)
}.withEndAction {
this.visibility = View.GONE
effect.reset(this)
onDone?.invoke()
}.start()
}
fun View.showOrHideAnimated(
predicate: Boolean,
effect: Motion,
duration: Duration = Duration.MEDIUM,
onDone: (() -> Unit)? = null
) {
if (predicate) {
showAnimated(effect, duration, onDone)
} else {
hideAnimated(effect, duration, onDone)
}
}