爲了買彩票,我寫了這個控件

0.

最近偶爾會買個雙色球,一週買個6塊錢的,也很少,就是湊個熱鬧,爲生活添加個小情趣。由於不會選號,每次都是機選,做爲一個陰謀論者,我以爲機選可能不夠「隨機」,爲此我決定本身寫個程序爲我選號,爲此我模仿老虎機寫了一個控件。先上圖android

1.

先設計一下git

1.1支持從數字和數組獲取數據

1.2繪製兩個數字,當前數字和下一個數字

1.3設置便宜量,並實現加速

1.4開始和中止,中止時添加回調

1.5支持設置文字大小與顏色

2.

廢話少說,上代碼github

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方法canvas

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方法bash

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也不等於控件高度,說明處於一箇中間狀態,那麼就讓它移到下一個位置,並調用回調函數。其餘的也沒什麼關鍵了,各位有須要的看代碼就行了ide

3.

github函數

關注個人公衆號post

相關文章
相關標籤/搜索