上次想写个时钟,在过程中写成了一个正在加载的View,当时没有继续写下去,这次花了点事件把这个时钟写完了。记录一下。
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import com.mark.jetpackpaging.R
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.min
class ClockView : View {
private val wrapWidth = 200f
private var outCircleWidth: Float = 20f
private var outCircleColor: Int = Color.BLACK
private var insideCircleColor: Int = Color.RED
private var insideCircleWidth: Float = 10f
private var hourColor: Int = Color.BLACK
private var minuteColor: Int = Color.BLACK
private var secondColor: Int = Color.BLACK
private var numberSize: Float = 20f
private var numberWidth: Float = 20f
private var numberColor: Int = Color.BLACK
private val mOutCirclePaint = Paint()
private val mInsideCirclePaint = Paint()
private val mHourPaint = Paint()
private val mMinutePaint = Paint()
private val mSecondPaint = Paint()
private val mNumberPaint = Paint()
private var hourNumber = 7
private var minuteNumber = 45
private var secondnumber = 50
private lateinit var curDate: String
private var mWidthHeight = 0f
constructor(context: Context) : this(context, null!!)
constructor(context: Context, attributeSet: AttributeSet) : this(context, attributeSet, 0)
constructor(context: Context, attributeSet: AttributeSet, style: Int) : super(
context,
attributeSet,
style
) {
val obtainStyledAttributes =
context.obtainStyledAttributes(attributeSet, R.styleable.ClockView)
outCircleWidth =
obtainStyledAttributes.getFloat(R.styleable.ClockView_out_circle_width, 20f)
insideCircleWidth =
obtainStyledAttributes.getFloat(R.styleable.ClockView_inside_circle_width, 10f)
numberSize = obtainStyledAttributes.getFloat(R.styleable.ClockView_number_size, 20f)
numberWidth = obtainStyledAttributes.getFloat(R.styleable.ClockView_number_width, 20f)
outCircleColor =
obtainStyledAttributes.getColor(R.styleable.ClockView_out_circle_color, Color.BLACK)
insideCircleColor =
obtainStyledAttributes.getColor(R.styleable.ClockView_inside_circle_color, Color.RED)
hourColor = obtainStyledAttributes.getColor(R.styleable.ClockView_hour_color, Color.BLACK)
minuteColor =
obtainStyledAttributes.getColor(R.styleable.ClockView_minute_color, Color.BLACK)
secondColor =
obtainStyledAttributes.getColor(R.styleable.ClockView_second_color, Color.BLACK)
numberColor =
obtainStyledAttributes.getColor(R.styleable.ClockView_number_color, Color.BLACK)
mOutCirclePaint.color = outCircleColor
mOutCirclePaint.strokeWidth = outCircleWidth
mOutCirclePaint.style = Paint.Style.STROKE
mOutCirclePaint.isAntiAlias = true
mInsideCirclePaint.color = insideCircleColor
mInsideCirclePaint.strokeWidth = insideCircleWidth
mInsideCirclePaint.style = Paint.Style.FILL
mInsideCirclePaint.isAntiAlias = true
mHourPaint.color = hourColor
mHourPaint.strokeWidth = numberWidth * 4
mHourPaint.style = Paint.Style.FILL
mHourPaint.isAntiAlias = true
mMinutePaint.color = minuteColor
mMinutePaint.strokeWidth = numberWidth * 3
mMinutePaint.style = Paint.Style.FILL
mMinutePaint.isAntiAlias = true
mSecondPaint.color = secondColor
mSecondPaint.strokeWidth = numberWidth * 2
mSecondPaint.style = Paint.Style.FILL
mSecondPaint.isAntiAlias = true
mNumberPaint.color = numberColor
mNumberPaint.strokeWidth = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
numberWidth,
resources.displayMetrics
)
mNumberPaint.textSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
numberSize,
resources.displayMetrics
)
mNumberPaint.style = Paint.Style.FILL
mNumberPaint.isAntiAlias = true
obtainStyledAttributes.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
mWidthHeight =
if ((widthMode == MeasureSpec.AT_MOST) and (heightMode == MeasureSpec.AT_MOST)) {
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
wrapWidth,
resources.displayMetrics
)
} else {
min(widthSize, heightSize).toFloat()
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
//画外圈
canvas?.drawCircle(
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
mWidthHeight / 2,
mOutCirclePaint
)
//画内圈
canvas?.drawCircle(
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
insideCircleWidth,
mInsideCirclePaint
)
canvas?.drawText(
curDate,
mWidthHeight / 2 + 100.toFloat(),
mWidthHeight / 2.toFloat(),
mNumberPaint
)
canvas?.save()
var length: Float
for (i in 0..59) {
if (i % 5 == 0) {
length = 40f
} else {
length = 20f
}
canvas?.drawLine(
mWidthHeight / 2.toFloat(),
20f,
mWidthHeight / 2.toFloat(),
20 + length,
mNumberPaint
)
canvas?.rotate(6f, mWidthHeight / 2.toFloat(), mWidthHeight / 2.toFloat())
}
canvas?.restore()
canvas?.save()
for (i in 1..12) {
var number = if ((i + 11) % 12 == 0) 12 else (i + 11) % 12
canvas?.drawText(
"$number",
mWidthHeight / 2.toFloat(),
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
40F,
resources.displayMetrics
),
mNumberPaint
)
canvas?.rotate(30f, mWidthHeight / 2.toFloat(), mWidthHeight / 2.toFloat())
}
canvas?.restore()
canvas?.save()
canvas?.rotate(-90F, mWidthHeight / 2.toFloat(), mWidthHeight / 2.toFloat())
canvas?.rotate(
(hourNumber * 30 + minuteNumber * 0.5).toFloat(),
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat()
)
canvas?.drawLine(
mWidthHeight / 2.toFloat() + mWidthHeight / 4,
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
mHourPaint
)
canvas?.restore()
canvas?.save()
canvas?.rotate(-90F, mWidthHeight / 2.toFloat(), mWidthHeight / 2.toFloat())
canvas?.rotate(
(minuteNumber * 6 + secondnumber / 360).toFloat(),
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat()
)
canvas?.drawLine(
mWidthHeight / 2.toFloat() + mWidthHeight / 4 + 100,
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
mMinutePaint
)
canvas?.restore()
canvas?.rotate(-90F, mWidthHeight / 2.toFloat(), mWidthHeight / 2.toFloat())
// canvas?.save()
canvas?.rotate(
(secondnumber * 6).toFloat(),
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat()
)
canvas?.drawLine(
mWidthHeight / 2.toFloat() + mWidthHeight / 4 + 200,
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
mWidthHeight / 2.toFloat(),
mSecondPaint
)
}
fun setDate(date: Date) {
val hh = SimpleDateFormat("hh").format(date).toInt()
val mm = SimpleDateFormat("mm").format(date).toInt()
val ss = SimpleDateFormat("ss").format(date).toInt()
val date = SimpleDateFormat("MM-dd").format(date)
hourNumber = hh
minuteNumber = mm
secondnumber = ss
curDate = date
invalidate()
}
}
在style.xml里面定义属性
<declare-styleable name="ClockView">
<attr name="out_circle_width" format="float" />
<attr name="out_circle_color" format="color" />
<attr name="inside_circle_width" format="dimension" />
<attr name="inside_circle_color" format="color" />
<attr name="point_color" format="color" />
<attr name="point_width" format="color" />
<attr name="hour_color" format="color" />
<attr name="minute_color" format="color" />
<attr name="second_color" format="color" />
<attr name="number_size" format="float" />
<attr name="number_width" format="float" />
<attr name="number_color" format="color" />
</declare-styleable>
使用的时候就可以用这些属性了。