为了买彩票,我写了这个控件
2019-03-10 本文已影响1人
a49f87ef5d4f
0.
最近偶尔会买个双色球,一周买个6块钱的,也不多,就是凑个热闹,为生活添加个小情趣。因为不会选号,每次都是机选,作为一个阴谋论者,我觉得机选可能不够“随机”,为此我决定自己写个程序为我选号,为此我模仿老虎机写了一个控件。先上图
image1.
先设计一下
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关注我的公众号