為了買彩票,我寫了這個控制元件
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.

image
關注我的公眾號