Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import android.animation.Animator
- import android.animation.AnimatorListenerAdapter
- import android.animation.AnimatorSet
- import android.animation.ObjectAnimator
- import android.annotation.TargetApi
- import android.graphics.Outline
- import android.graphics.Rect
- import android.os.Build
- import android.transition.Transition
- import android.transition.TransitionValues
- import android.view.View
- import android.view.ViewAnimationUtils
- import android.view.ViewGroup
- import android.view.ViewOutlineProvider
- import android.view.animation.LinearInterpolator
- import kotlin.math.roundToInt
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- class CircularReveal : Transition() {
- companion object {
- private const val DEFAULT_DURATION = 200L
- private const val BOUNDS = "BOUNDS"
- private val TRANSITION_PROPERTIES = arrayOf(BOUNDS)
- }
- init {
- duration = DEFAULT_DURATION
- interpolator = LinearInterpolator()
- }
- override fun getTransitionProperties() = TRANSITION_PROPERTIES
- override fun captureStartValues(transitionValues: TransitionValues) {
- captureValues(transitionValues)
- }
- override fun captureEndValues(transitionValues: TransitionValues) {
- captureValues(transitionValues)
- }
- override fun createAnimator(
- sceneRoot: ViewGroup,
- startValues: TransitionValues?,
- endValues: TransitionValues?
- ): Animator? {
- if (startValues == null || endValues == null) return null
- val startBounds = startValues.values[BOUNDS] as Rect
- val endBounds = endValues.values[BOUNDS] as Rect
- val isReveal = endBounds.width() > startBounds.width()
- val view = endValues.view
- val translationX = startBounds.centerX() - endBounds.centerX()
- val translationY = startBounds.centerY() - endBounds.centerY()
- if (isReveal) {
- view.translationX = translationX.toFloat()
- view.translationY = translationY.toFloat()
- }
- val translate = ObjectAnimator.ofFloat(
- view,
- View.TRANSLATION_X,
- View.TRANSLATION_Y,
- if (isReveal) pathMotion.getPath(translationX.toFloat(), translationY.toFloat(), 0f, 0f)
- else pathMotion.getPath(0f, 0f, (-translationX).toFloat(), (-translationY).toFloat())
- )
- val startScale = startBounds.width() / endBounds.width().toFloat()
- val endScale = endBounds.width() / startBounds.width().toFloat()
- val resize = AnimatorSet().apply {
- if (isReveal) {
- play(ObjectAnimator.ofFloat(view, View.SCALE_X, startScale, 1F))
- .with(ObjectAnimator.ofFloat(view, View.SCALE_Y, startScale, 1F))
- } else {
- play(ObjectAnimator.ofFloat(view, View.SCALE_X, endScale))
- .with(ObjectAnimator.ofFloat(view, View.SCALE_Y, endScale))
- }
- }
- val circularReveal: Animator = if (isReveal) {
- ViewAnimationUtils.createCircularReveal(
- view,
- view.width / 2,
- view.height / 2,
- startBounds.width() / 2F * endScale,
- Math.hypot(endBounds.width().toDouble(), endBounds.height().toDouble()).toFloat()
- )
- } else {
- view.layout(startBounds.left, startBounds.top, startBounds.right, startBounds.bottom)
- ViewAnimationUtils.createCircularReveal(
- view,
- view.width / 2,
- view.height / 2,
- Math.hypot(startBounds.width().toDouble(), startBounds.height().toDouble()).toFloat(),
- endBounds.width() / 2F * startScale
- ).apply {
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- view.outlineProvider = object : ViewOutlineProvider() {
- override fun getOutline(view: View, outline: Outline) {
- val left = ((view.width - endBounds.width() * startScale) / 2).roundToInt()
- val top = ((view.height - endBounds.height() * startScale) / 2).roundToInt()
- val right = left + Math.min(view.width, view.height)
- val bottom = top + Math.min(view.width, view.height)
- outline.setOval(left, top, right, bottom)
- view.clipToOutline = true
- }
- }
- }
- })
- }
- }
- val transition = AnimatorSet().apply {
- playTogether(translate, circularReveal, resize)
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- view.overlay.clear()
- }
- })
- }
- return NoPauseAnimator(transition)
- }
- private fun captureValues(transitionValues: TransitionValues) {
- val view = transitionValues.view
- if (view == null || view.width <= 0 || view.height <= 0) return
- transitionValues.values[BOUNDS] = Rect(view.left, view.top, view.right, view.bottom)
- }
- }
Add Comment
Please, Sign In to add comment