为了买彩票,我写了这个控件

作者: a49f87ef5d4f | 来源:发表于2019-03-10 22:03 被阅读1次

    0.

    最近偶尔会买个双色球,一周买个6块钱的,也不多,就是凑个热闹,为生活添加个小情趣。因为不会选号,每次都是机选,作为一个阴谋论者,我觉得机选可能不够“随机”,为此我决定自己写个程序为我选号,为此我模仿老虎机写了一个控件。先上图

    image

    1.

    先设计一下

    1.1支持从数字和数组获取数据

    1.2绘制两个数字,当前数字和下一个数字

    1.3设置便宜量,并实现加速

    1.4开始和停止,停止时添加回调

    1.5支持设置文字大小与颜色

    2.

    废话少说,上代码

    package com.skateboard.numberrunningview
    
    import android.content.Context
    import android.graphics.Canvas
    import android.graphics.Color
    import android.graphics.Paint
    import android.support.v4.view.ViewCompat
    import android.util.AttributeSet
    import android.view.View
    
    class NumberRunningView(context: Context, attributes: AttributeSet?) : View(context, attributes) {
    
    
        private var numberColor = Color.WHITE
    
        private var numberSize = 15.0f
        
        //开始时的数字或者数组下标
        var min = 0
       //最大的数字或者数组下标
        var max = 0
       //当前要绘制数字或者数组下标
        private var now = min
       //每次刷新移动的距离
        private var offset = 0
    
        private var paint = Paint(Paint.ANTI_ALIAS_FLAG)
    
        private var isStart = false
    
        var maxSpeed = 10f
        //当前移动速度
        private var curSpeed = 0f
        //加速度增量
        private var speedOffset = 0.1f
    
        var dataList: List<Int>? = null
            set(value) {
                field = value
                min = 0
                max = (value?.size ?: 1) - 1
                now = min
                offset = 0
            }
    
        var onNumberSelectedListener: OnNumberSelectedListenern? = null
    
        init {
    
            if (attributes != null) {
                parseAttrs(attributes)
            }
            initPaint()
        }
    
        constructor(context: Context) : this(context, null)
    
        private fun parseAttrs(attributes: AttributeSet) {
    
            val typedArray = context.obtainStyledAttributes(attributes, R.styleable.NumberRunningView)
            min = typedArray.getInt(R.styleable.NumberRunningView_min, min)
            max = typedArray.getInt(R.styleable.NumberRunningView_max, max)
            maxSpeed = typedArray.getFloat(R.styleable.NumberRunningView_maxSpeed, maxSpeed)
            numberColor = typedArray.getColor(R.styleable.NumberRunningView_numberColor, numberColor)
            numberSize = typedArray.getDimension(R.styleable.NumberRunningView_numberSize, numberSize)
            speedOffset = typedArray.getFloat(R.styleable.NumberRunningView_speedOffset, 0.1f)
            typedArray.recycle()
            now = min
        }
    
        private fun initPaint() {
            paint.textSize = numberSize
            paint.color = numberColor
        }
    
        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            canvas?.let {
                drawNow(it)
                drawNext(it)
                calCurSpeed()
                calOffset()
            }
        }
    
        private fun calCurSpeed() {
            curSpeed += speedOffset
            if (curSpeed > maxSpeed) curSpeed = maxSpeed
        }
    
        private fun drawNow(canvas: Canvas) {
            val curDataList = dataList
            var nowNum = "0"
            nowNum = if (curDataList != null) {
                curDataList[now].toString()
            } else {
                now.toString()
            }
            val numWidth = paint.measureText(nowNum)
            canvas.drawText(nowNum, width / 2 - numWidth / 2, height / 2 - offset + paint.textSize / 2, paint)
        }
    
    
        private fun drawNext(canvas: Canvas) {
            val curDataList = dataList
            var nextNum = ""
            if (curDataList == null) {
                nextNum = if (now + 1 > max) {
                    min.toString()
                } else {
                    (now + 1).toString()
                }
    
            } else {
                nextNum = if (now + 1 > max) {
                    curDataList[min].toString()
                } else {
                    (curDataList[now + 1]).toString()
                }
            }
            val numWidth = paint.measureText(nextNum)
            canvas.drawText(nextNum, width / 2 - numWidth / 2, 1.5f * height - offset + paint.textSize / 2, paint)
        }
    
        private fun calOffset() {
            if (isStart) {
                if (offset == height) {
                    offset = 0
                    if (now + 1 > max) {
                        now = min
                    } else {
                        now += 1
                    }
                } else if (offset + curSpeed > height) {
                    offset = height
                } else {
                    offset = (offset + curSpeed).toInt()
                }
                postInvalidate()
            } else {
                if (offset != 0 && offset != height) {
                    offset = if (offset + curSpeed > height) {
                        height
                    } else {
                        (offset + curSpeed).toInt()
                    }
                    postInvalidate()
                } else {
                    if (offset == 0) {
                        val curDataList = dataList
                        if (curDataList != null) {
                            onNumberSelectedListener?.onNumberSelected(curDataList[now])
                        } else {
                            onNumberSelectedListener?.onNumberSelected(now)
                        }
                    } else {
                        val curDataList = dataList
                        if (curDataList != null) {
                            onNumberSelectedListener?.onNumberSelected(if (now == max) curDataList[min] else curDataList[now + 1])
                        } else {
                            onNumberSelectedListener?.onNumberSelected(if (now == max) min else now + 1)
                        }
                    }
                }
            }
        }
    
        fun start() {
            if (isStart) {
                return
            }
            curSpeed = 0f
            isStart = true
            if (ViewCompat.isAttachedToWindow(this)) {
                postInvalidate()
            }
        }
    
        fun stop() {
            isStart = false
        }
       
        interface OnNumberSelectedListenern {
    
            fun onNumberSelected(num: Int)
        }
    }
    

    代码比较简单,没什么难度,先看onDraw方法

     override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            canvas?.let {
                drawNow(it)
                drawNext(it)
                calCurSpeed()
                calOffset()
            }
        }
    

    绘制当前数字,绘制下一个数字,计算当前速度,计算偏移量,这个速度主要是用来看起来开始时数字的翻转有一个加速的过程。看一下drawNow方法

     private fun drawNow(canvas: Canvas) {
            val curDataList = dataList
            var nowNum = "0"
            nowNum = if (curDataList != null) {
                curDataList[now].toString()
            } else {
                now.toString()
            }
            val numWidth = paint.measureText(nowNum)
            canvas.drawText(nowNum, width / 2 - numWidth / 2, height / 2 - offset + paint.textSize / 2, paint)
        }
    

    首先根据数据源的不同获取的数据,然后计算文字绘制的位置,然后绘制
    drawNext大同小异,无非就是一个下一个数字的判断问题
    calOffset方法

     private fun calOffset() {
            if (isStart) {
                if (offset == height) {
                    offset = 0
                    if (now + 1 > max) {
                        now = min
                    } else {
                        now += 1
                    }
                } else if (offset + curSpeed > height) {
                    offset = height
                } else {
                    offset = (offset + curSpeed).toInt()
                }
                postInvalidate()
            } else {
                if (offset != 0 && offset != height) {
                    offset = if (offset + curSpeed > height) {
                        height
                    } else {
                        (offset + curSpeed).toInt()
                    }
                    postInvalidate()
                } else {
                    if (offset == 0) {
                        val curDataList = dataList
                        if (curDataList != null) {
                            onNumberSelectedListener?.onNumberSelected(curDataList[now])
                        } else {
                            onNumberSelectedListener?.onNumberSelected(now)
                        }
                    } else {
                        val curDataList = dataList
                        if (curDataList != null) {
                            onNumberSelectedListener?.onNumberSelected(if (now == max) curDataList[min] else curDataList[now + 1])
                        } else {
                            onNumberSelectedListener?.onNumberSelected(if (now == max) min else now + 1)
                        }
                    }
                }
            }
        }
    

    如果处于运行状态,先判断控件当前偏移量,如果等于控件高度,那么就重置为0,然后将now置为下一个数,否则就加上速度重新计算偏移量。如果不处于运行状态,那么判断当前的偏移量,如果既不等于0也不等于控件高度,说明处于一个中间状态,那么就让它移到下一个位置,并调用回调函数。其他的也没什么关键了,各位有需要的看代码就好了

    3.

    github

    image

    关注我的公众号

    相关文章

      网友评论

        本文标题:为了买彩票,我写了这个控件

        本文链接:https://www.haomeiwen.com/subject/gkxmpqtx.html