/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.keyguard import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.TimeInterpolator import android.animation.ValueAnimator import android.graphics.Canvas import android.graphics.Typeface import android.text.Layout import android.util.SparseArray private const val TAG_WGHT = "wght" private const val DEFAULT_ANIMATION_DURATION: Long = 300 /** * This class provides text animation between two styles. * * Currently this class can provide text style animation for text weight and text size. For example * the simple view that draws text with animating text size is like as follows: * *
*
* class SimpleTextAnimation : View {
* @JvmOverloads constructor(...)
*
* private val layout: Layout = ... // Text layout, e.g. StaticLayout.
*
* // TextAnimator tells us when needs to be invalidate.
* private val animator = TextAnimator(layout) { invalidate() }
*
* override fun onDraw(canvas: Canvas) = animator.draw(canvas)
*
* // Change the text size with animation.
* fun setTextSize(sizePx: Float, animate: Boolean) {
* animator.setTextStyle(-1 /* unchanged weight */, sizePx, animate)
* }
* }
*
*
*/
class TextAnimator(
layout: Layout,
private val invalidateCallback: () -> Unit
) {
// Following two members are for mutable for testing purposes.
internal var textInterpolator: TextInterpolator = TextInterpolator(layout)
internal var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply {
duration = DEFAULT_ANIMATION_DURATION
addUpdateListener {
textInterpolator.progress = it.animatedValue as Float
invalidateCallback()
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
textInterpolator.rebase()
}
override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
})
}
private val typefaceCache = SparseArray