網(wǎng)站首頁 編程語言 正文
即刻點(diǎn)贊展示
點(diǎn)贊的數(shù)字增加和減少并不是整個(gè)替換,而是差異化替換。再加上動(dòng)畫效果就看的很舒服。
自己如何實(shí)現(xiàn)這種數(shù)字切換呢?
下面用一張圖來展示我的思路:
現(xiàn)在只需要根據(jù)這張圖,寫出對(duì)應(yīng)的動(dòng)畫即可。 分為2種場(chǎng)景:
- 數(shù)字+1:
- 差異化的數(shù)字從3號(hào)區(qū)域由漸變動(dòng)畫(透明度 0- 255) + 偏移動(dòng)畫 (3號(hào)區(qū)域繪制文字的基線,2號(hào)區(qū)域繪制文字的基線),將數(shù)字移動(dòng)到2號(hào)位置處
- 差異化的數(shù)字從2號(hào)區(qū)域由漸變動(dòng)畫(透明度 255- 0) + 偏移動(dòng)畫(2號(hào)區(qū)域繪制文字的基線,1號(hào)區(qū)域繪制文字的基線),將數(shù)字移動(dòng)到1號(hào)位置處
- 數(shù)字-1
- 差異化的數(shù)字從1號(hào)區(qū)域由漸變動(dòng)畫(透明度 0- 255) + 偏移動(dòng)畫 (1號(hào)區(qū)域繪制文字的基線,2號(hào)區(qū)域繪制文字的基線),將數(shù)字移動(dòng)到2號(hào)位置處
- 差異化的數(shù)字從2號(hào)區(qū)域由漸變動(dòng)畫(透明度 255- 0) + 偏移動(dòng)畫(2號(hào)區(qū)域繪制文字的基線,3號(hào)區(qū)域繪制文字的基線),將數(shù)字移動(dòng)到3號(hào)位置處
公共部分就是: 不變的文字不需要做任何處理,繪制在2號(hào)區(qū)域就行。繪制差異化文字時(shí),需要加上不變的文字的寬度就行。
效果展示
源碼
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)
}
}
}
總結(jié)
原文鏈接:https://juejin.cn/post/7179181214530551867
相關(guān)推薦
- 2022-12-11 C語言中求解圖形的問題_C 語言
- 2022-11-20 Postgresql刪除數(shù)據(jù)庫表中重復(fù)數(shù)據(jù)的幾種方法詳解_PostgreSQL
- 2022-10-15 python中mpi4py的所有基礎(chǔ)使用案例詳解_python
- 2022-08-27 C#從前面或后面按指定數(shù)量刪除字符串_C#教程
- 2022-07-02 iview中的表格render搭配使用Tooltip 文字提示
- 2024-04-03 objectMapper(字符串轉(zhuǎn)對(duì)象)
- 2023-01-03 python案例中Flask全局配置示例詳解_python
- 2023-03-16 redis如何取hash的值_Redis
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支