跳动+滚动的数字

430 阅读2分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。
效果1跳动的数字:

numjump.gif 实现思路拆分要展示的数字然后找到对应的图片将他们绘制出来。

class OneViewImgJumpView : View {
    var oneNumWidth = 0f // 文字的高度
    var currentNum = "1"
    var mMatrix = Matrix()
    var imgListBitmap = ArrayList<Bitmap>()
    val mPaint by lazy {
        Paint()
    }
    private val numImgList = intArrayOf(
        R.drawable.num0,
        R.drawable.num1,
        R.drawable.num2,
        R.drawable.num3,
        R.drawable.num4,
        R.drawable.num5,
        R.drawable.num6,
        R.drawable.num7,
        R.drawable.num8,
        R.drawable.num9,
        R.drawable.num0,
        R.drawable.num1,
        R.drawable.num2,
        R.drawable.num3,
        R.drawable.num4,
        R.drawable.num5,
        R.drawable.num6,
        R.drawable.num7,
        R.drawable.num8,
        R.drawable.num9
    )

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
        val options = BitmapFactory.Options()

        numImgList.forEach {
            var bitmap = BitmapFactory.decodeResource(resources, it, options)
            imgListBitmap.add(zoomImage(bitmap, 70.0, 100.0))
        }
    }

    fun zoomImage(
        bgimage: Bitmap, newWidth: Double,
        newHeight: Double
    ): Bitmap {
        // 获取这个图片的宽和高
        val width = bgimage.width.toFloat()
        val height = bgimage.height.toFloat()
        // 创建操作图片用的matrix对象
        val matrix = Matrix()
        // 计算宽高缩放率
        val scaleWidth = newWidth.toFloat() / width
        val scaleHeight = newHeight.toFloat() / height
        // 缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight)
        return Bitmap.createBitmap(bgimage, 0, 0, width.toInt(), height.toInt(), matrix, true)
    }


    // 以view中心为缩放点,由初始状态放大两倍
    var animation = ScaleAnimation(
        1.0f, 1.3f, 1.0f, 1.3f,
        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f
    ).apply {
        setDuration(50)
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        oneNumWidth = 80f
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        for(index in currentNum.indices){
            if (index != 0) {
                canvas?.translate(oneNumWidth, 0f)
            }
            canvas?.drawBitmap(imgListBitmap[currentNum[index] - '0'], mMatrix, mPaint)
        }
    }

    fun addNum(targetNum: Int) {
        currentNum = targetNum.toString()
        startAnimation(animation)
    }

}

效果2滚动的数字:

ddd.gif

代码:

package com.example.myapplication.jumpstudy

import android.content.Context
import android.graphics.*
import android.text.TextPaint
import android.util.AttributeSet
import android.view.View
import android.view.animation.Animation
import android.view.animation.ScaleAnimation
import android.widget.Scroller
import com.example.myapplication.R


class NumImgJumpView : View {

    private val numImgList = intArrayOf(
        R.drawable.num0,
        R.drawable.num1,
        R.drawable.num2,
        R.drawable.num3,
        R.drawable.num4,
        R.drawable.num5,
        R.drawable.num6,
        R.drawable.num7,
        R.drawable.num8,
        R.drawable.num9,
        R.drawable.num0,
        R.drawable.num1,
        R.drawable.num2,
        R.drawable.num3,
        R.drawable.num4,
        R.drawable.num5,
        R.drawable.num6,
        R.drawable.num7,
        R.drawable.num8,
        R.drawable.num9
    )
    var imgListBitmap = ArrayList<Bitmap>()
    var oneNumWidth = 0f
    var oneNumHeight = 0f // 文字的高度
    var currentNum = "1"
    var nextNum = "2"
    var targetNum = 6//目标值
    val mScroller: Scroller by lazy {
        Scroller(context)
    }

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
        numImgList.forEach {
            var bitmap = BitmapFactory.decodeResource(resources, it)
            imgListBitmap.add(zoomImage(bitmap, 70.0, 100.0))
        }
    }

    fun zoomImage(
        bgimage: Bitmap, newWidth: Double,
        newHeight: Double
    ): Bitmap {
        // 获取这个图片的宽和高
        val width = bgimage.width.toFloat()
        val height = bgimage.height.toFloat()
        // 创建操作图片用的matrix对象
        val matrix = Matrix()
        // 计算宽高缩放率
        val scaleWidth = newWidth.toFloat() / width
        val scaleHeight = newHeight.toFloat() / height
        // 缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight)
        return Bitmap.createBitmap(bgimage, 0, 0, width.toInt(), height.toInt(), matrix, true)
    }

    // 以view中心为缩放点,由初始状态放大两倍
    var animation = ScaleAnimation(
        1.0f, 1.5f, 1.0f, 1.5f,
        Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f
    )

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        oneNumHeight = 100f
        oneNumWidth = 70f
        setMeasuredDimension(widthMeasureSpec, (oneNumHeight * 1).toInt())
    }

    val mPaint by lazy {
        Paint()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        for (index in currentNum.indices) {
            var distanceY = if (currentNum.length == nextNum.length && currentNum.length > 1) {
                // 表示要进位了。
                var s11 = currentNum[index] - '0'
                var s22 = nextNum[index] - '0'
                if (s22 - s11 != 0) {
                    // 表示进位
                    (oneNumHeight * (currentNum.toInt() - 1))
                } else {
                    mScroller.currY.toFloat()
                }
            } else {
                (oneNumHeight * (currentNum.toInt() - 1))
            }
            canvas?.drawBitmap(
                imgListBitmap[currentNum[index] - '0'],
                oneNumWidth * index,
                distanceY,
                mPaint
            )
        }

        for (index in nextNum.indices) {
            var distanceY = if (currentNum.length == nextNum.length && currentNum.length > 1) {
                // 表示要进位了。
                var s11 = currentNum[index] - '0'
                var s22 = nextNum[index] - '0'
                if (s22 - s11 != 0) {
                    // 表示进位
                    (oneNumHeight * (nextNum.toInt() - 1))
                } else {
                    mScroller.currY.toFloat()
                }
            } else {
                (oneNumHeight * (nextNum.toInt() - 1))
            }
            canvas?.drawBitmap(
                imgListBitmap[nextNum[index] - '0'],
                oneNumWidth * index,
                distanceY,
                mPaint
            )
        }
        var haveMoveDistance = mScroller.currY // 已经移动的距离
        if (haveMoveDistance >= (currentNum.toInt() * oneNumHeight)) {
            // 代表第一个完全超越
            currentNum = nextNum.toString()
            nextNum = (currentNum.toInt() + 1).toString()
        }
    }

    fun addNum(targetNum: Int) {
        this.targetNum = targetNum
        mScroller.startScroll(
            mScroller.currX,
            mScroller.currY,
            0,
            ((targetNum - 1) * oneNumHeight - mScroller.currY).toInt()
        )
        postInvalidate()
    }

    override fun computeScroll() {
        super.computeScroll()
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.currX, mScroller.currY)
            postInvalidate()
        }
    }
}