Android自定义View模仿即刻点赞数字切换效果实例
目录
- 即刻点赞展示
- 自己如何实现这种数字切换呢?
- 效果展示
- 源码
- 总结
即刻点赞展示
点赞的数字增加和减少并不是整个替换,而是差异化替换。再加上动画效果就看的很舒服。
自己如何实现这种数字切换呢?
下面用一张图来展示我的思路:
现在只需要根据这张图,写出对应的动画即可。 分为2种场景:
- 数字+1:
- 差异化的数字从3号区域由渐变动画(透明度 0- 255) + 偏移动画 (3号区域绘制文字的基线,2号区域绘制文字的基线),将数字移动到2号位置处
- 差异化的数字从2号区域由渐变动画(透明度 255- 0) + 偏移动画(2号区域绘制文字的基线,1号区域绘制文字的基线),将数字移动到1号位置处
- 数字-1
- 差异化的数字从1号区域由渐变动画(透明度 0- 255) + 偏移动画 (1号区域绘制文字的基线,2号区域绘制文字的基线),将数字移动到2号位置处
- 差异化的数字从2号区域由渐变动画(透明度 255- 0) + 偏移动画(2号区域绘制文字的基线,3号区域绘制文字的基线),将数字移动到3号位置处
公共部分就是: 不变的文字不需要做任何处理,绘制在2号区域就行。绘制差异化文字时,需要加上不变的文字的宽度就行。
效果展示
源码
class LikeView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { private val paint = Paint().also { it.isAntiAlias = true it.textSize = 200f } private val textRect0 = Rect(300, 100, 800, 300) private val textRect1 = Rect(300, 300, 800, 500) private val textRect2 = Rect(300, 500, 800, 700) private var nextNumberAlpha: Int = 0 set(value) { field = value invalidate() } private var currentNumberAlpha: Int = 255 set(value) { field = value invalidate() } private var offsetPercent = 0f set(value) { field = value invalidate() } private val fontMetrics: FontMetrics = paint.fontMetrics private var currentNumber = 99 private var nextNumber = 0 private var motionLess = currentNumber.toString() private var currentMotion = "" private var nextMotion = "" private val animator: ObjectAnimator by lazy { val nextNumberAlphaAnimator = PropertyValuesHolder.ofInt("nextNumberAlpha", 0, 255) val offsetPercentAnimator = PropertyValuesHolder.ofFloat("offsetPercent", 0f, 1f) val currentNumberAlphaAnimator = PropertyValuesHolder.ofInt("currentNumberAlpha", 255, 0) val animator = ObjectAnimator.ofPropertyValuesHolder( this, nextNumberAlphaAnimator, offsetPercentAnimator, currentNumberAlphaAnimator ) animator.duration = 200 animator.interpolator = DecelerateInterpolator() animator.addListener( onEnd = { currentNumber = nextNumber } ) animator } override fun onDraw(canvas: Canvas) { paint.alpha = 255 paint.color = Color.LTGRAY canvas.drawRect(textRect0, paint) paint.color = Color.RED canvas.drawRect(textRect1, paint) paint.color = Color.GREEN canvas.drawRect(textRect2, paint) paint.color = Color.BLACK if (motionLess.isNotEmpty()) { drawText(canvas, motionLess, textRect1, 0f) } if (nextMotion.isEmpty() || currentMotion.isEmpty()) { return } val textHorizontalOffset = if (motionLess.isNotEmpty()) paint.measureText(motionLess) else 0f if (nextNumber > currentNumber) { paint.alpha = currentNumberAlpha drawText(canvas, currentMotion, textRect1, textHorizontalOffset, -offsetPercent) paint.alpha = nextNumberAlpha drawText(canvas, nextMotion, textRect2, textHorizontalOffset, -offsetPercent) } else { paint.alpha = nextNumberAlpha drawText(canvas, nextMotion, textRect0, textHorizontalOffset, offsetPercent) paint.alpha = currentNumberAlpha drawText(canvas, currentMotion, textRect1, textHorizontalOffset, offsetPercent) } } private fun drawText( canvas: Canvas, text: String, rect: Rect, textHorizontalOffset: Float = 0f, offsetPercent: Float = 0f ) { canvas.drawText( text, rect.left.toFloat() + textHorizontalOffset, rect.top + (rect.bottom - rect.top) / 2f - (fontMetrics.bottom + fontMetrics.top) / 2f + offsetPercent * 200, paint ) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() animator.end() } fun plus() { if (currentNumber == Int.MAX_VALUE) { return } nextNumber = currentNumber + 1 processText(findEqualsStringIndex()) if (animator.isRunning) { return } animator.start() } fun minus() { if (currentNumber == 0) { return } nextNumber = currentNumber - 1 processText(findEqualsStringIndex()) if (animator.isRunning) { return } animator.start() } private fun findEqualsStringIndex(): Int { var equalIndex = -1 val nextNumberStr = nextNumber.toString() val currentNumberStr = currentNumber.toString() val endIndex = min(currentNumberStr.length, nextNumberStr.length) - 1 for (index in 0..endIndex) { if (nextNumberStr[index] != currentNumberStr[index]) { break } equalIndex = index } return equalIndex } private fun processText(index: Int) { val currentNumberStr = currentNumber.toString() val nextNumberStr = nextNumber.toString() if (index == -1) { motionLess = "" currentMotion = currentNumberStr nextMotion = nextNumberStr } else { motionLess = currentNumberStr.substring(0, index + 1) currentMotion = currentNumberStr.substring(index + 1) nextMotion = nextNumberStr.substring(index + 1) } } }
总结
到此这篇关于Android自定义View模仿即刻点赞数字切换效果的文章就介绍到这了,更多相关Android模仿即刻点赞数字切换内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
赞 (0)