Android自定义View 时钟

上次想写个时钟,在过程中写成了一个正在加载的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>

使用的时候就可以用这些属性了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值