首页 > 其他分享 >Android开发 自定义View_时钟

Android开发 自定义View_时钟

时间:2023-01-29 21:13:55浏览次数:64  
标签:canvas 自定义 val mCentralPoint toFloat private Android Math View

前言

  自定义View实现时钟涉及到三角函数,如果你对三角函数不甚了解或者已经遗忘,请参考我的博客:圆与三角函数的公式与使用   这篇博客详细解释了三角函数公式与对应坐标关系。里面也举例了时钟的实现,只不过是用Jetpack compose的自定义View实现的时钟。而这篇博客用老的方式继承View实现。

效果图

代码

/**
 * 时钟View
 */
class ClockView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
    private var mCalendar = Calendar.getInstance()
    private var mWidth = 0
    private var mHeight = 0
    private var mRadius = 0
    private val mCentralPoint = Point()
    private val mHourPaint = Paint()
    private val mMinutePaint = Paint()
    private val mSecondsPaint = Paint()
    private val mScalePaint = Paint()
    private val mTextPaint = Paint()

    init {
        //时
        mHourPaint.color = Color.WHITE
        mHourPaint.flags = Paint.ANTI_ALIAS_FLAG
        mHourPaint.strokeWidth = 4f
        mHourPaint.strokeCap = Paint.Cap.ROUND
        //分
        mMinutePaint.color = Color.WHITE
        mMinutePaint.flags = Paint.ANTI_ALIAS_FLAG
        mMinutePaint.strokeWidth = 2f
        mMinutePaint.strokeCap = Paint.Cap.ROUND
        //秒
        mSecondsPaint.color = Color.RED
        mSecondsPaint.flags = Paint.ANTI_ALIAS_FLAG
        mSecondsPaint.strokeCap = Paint.Cap.ROUND
        //刻度
        mScalePaint.color = Color.WHITE
        mScalePaint.flags = Paint.ANTI_ALIAS_FLAG
        //文字
        mTextPaint.color = Color.WHITE
        mTextPaint.flags = Paint.ANTI_ALIAS_FLAG
        mTextPaint.textAlign = Paint.Align.CENTER
        mTextPaint.textSize = 25f
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        mWidth = MeasureSpec.getSize(widthMeasureSpec)
        mHeight = MeasureSpec.getSize(heightMeasureSpec)
        mCentralPoint.x = mWidth / 2
        mCentralPoint.y = mHeight / 2
        mRadius = if (mWidth > mHeight) mHeight / 2 else mWidth / 2
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        mCalendar = Calendar.getInstance()
        drawClockBackground(canvas)
        drawCurrentHour(canvas)
        drawCurrentMinute(canvas)
        drawCurrentSecond(canvas)
        postInvalidateDelayed(100)
    }

    /**
     * 绘制时钟背景,画文字与刻度
     */
    private fun drawClockBackground(canvas: Canvas) {
        //画表盘
        for (i in 1..60) {
            val angle = 360 / 60 * i + 48
            val o = angle * Math.PI / 180
            var scaleRadius = mRadius * 0.95 //刻度长度
            if (i % 5 == 2) {
                scaleRadius = mRadius * 0.90
            }
            val px1 = mCentralPoint.x + scaleRadius * Math.cos(o)
            val py1 = mCentralPoint.y - scaleRadius * Math.sin(o)

            val px2 = mCentralPoint.x + mRadius * Math.cos(o)
            val py2 = mCentralPoint.y - mRadius * Math.sin(o)
            canvas.drawLine(px1.toFloat(), py1.toFloat(), px2.toFloat(), py2.toFloat(), mScalePaint)
        }
        //画数字
        for (i in 1..12) {
            val textAngle = 360 / 12 * i + 90
            var textRadius = mRadius * 0.8 //数字的位置半径
            val textO = textAngle * Math.PI / 180
            val textPx = mCentralPoint.x + textRadius * Math.cos(textO)
            //因为文字有绘制基线导致12会比6显示更高一点,这样与时钟圆盘显示起来不在同一的圆心点上,这里减少圆心Y轴坐标做到
            val textPy = (mCentralPoint.y + 10) - textRadius * Math.sin(textO)
            val text = if (12 - i == 0) 12 else 12 - i
            canvas.drawText(text.toString(), textPx.toFloat(), textPy.toFloat(), mTextPaint)
        }
    }

    /**
     * 绘制小时指针
     */
    private fun drawCurrentHour(canvas: Canvas) {
        val hour = mCalendar.get(Calendar.HOUR)
        val minute = mCalendar.get(Calendar.MINUTE)
        //得出分钟角度,转成负数是希望以顺时针旋转
        var angle = -(360 / 12 * hour - 90)
        //补上当前分钟的角度到时钟上 >>> 当前分角度 除 12
        angle -= 360 / 60 * minute / 60
        val o = angle * Math.PI / 180
        val radius = mRadius * 0.6
        val px = mCentralPoint.x + radius * Math.cos(o)
        val py = mCentralPoint.y - radius * Math.sin(o)
        canvas.drawLine(
            mCentralPoint.x.toFloat(),
            mCentralPoint.y.toFloat(),
            px.toFloat(),
            py.toFloat(),
            mHourPaint
        )
    }

    /**
     * 绘制分钟指针
     */
    private fun drawCurrentMinute(canvas: Canvas) {
        val minute = mCalendar.get(Calendar.MINUTE)
        val second = mCalendar.get(Calendar.SECOND)
        //得出分钟角度,转成负数是希望以顺时针旋转
        var angle = -(360 / 60 * minute - 90)
        //补上当前秒的角度到分钟上 >>> 当前秒角度 除 60分钟
        angle -= 360 / 60 * second / 60
        val o = angle * Math.PI / 180
        val radius = mRadius * 0.7
        val px = mCentralPoint.x + radius * Math.cos(o)
        val py = mCentralPoint.y - radius * Math.sin(o)
        canvas.drawLine(
            mCentralPoint.x.toFloat(),
            mCentralPoint.y.toFloat(),
            px.toFloat(),
            py.toFloat(),
            mMinutePaint
        )
    }

    /**
     * 绘制秒指针
     */
    private fun drawCurrentSecond(canvas: Canvas) {
        val second = mCalendar.get(Calendar.SECOND)
        //得出秒角度,转成负数是希望以顺时针旋转
        val angle = -(360 / 60 * second - 90)
        val o = angle * Math.PI / 180
        val radius = mRadius * 0.75
        val px = mCentralPoint.x + radius * Math.cos(o)
        val py = mCentralPoint.y - radius * Math.sin(o)
        canvas.drawLine(
            mCentralPoint.x.toFloat(),
            mCentralPoint.y.toFloat(),
            px.toFloat(),
            py.toFloat(),
            mSecondsPaint
        )
    }
}

 

 

End

标签:canvas,自定义,val,mCentralPoint,toFloat,private,Android,Math,View
From: https://www.cnblogs.com/guanxinjing/p/17073817.html

相关文章

  • Table类:后台自定义条件筛选查询
    1、首先需要在控制器中定义开启变量,例如控制器:dayrui/App/Demo/Controllers/Admin/Home.php//数据表初始化protectedfunction_init($data){$this->......
  • svg之viewbox缩放
    先看个示例代码如下:<!DOCTYPEhtml><html><head> <metacharset="utf-8"> <title>svg-viewbox</title> <style> body{ text-align:center; } svg{ margin......
  • XnView 1.96.5
    非常棒的图像查看程序。支持150种图片格式,除一般的查看、浏览、幻灯显示等功能外,还自带30多面滤镜,方便编辑修改;可以批量转换文件格式,创建缩略图并生成网页,还可自己制作GIF......
  • 远程控制软件 TeamViewer 4.0.5459 简体中文版
    优点:没什么说的。亮点:支持直接拖放文件或目录到被控机器屏幕(目录),这个好!缺点:被控制的目标机器被锁定后无法使用屏幕连接访问,郁闷。。。啊下载地址:​​​http://vbcoder.qupan......
  • vue中多行(单行)文本溢出才会出现提示的自定义指令
     //以下代码可以直接粘贴进自己的`.vue`文件中查看效果<template><divclass="parent"><h3>标题</h3><divclass="child"v-ellipsis="3">{{msg......
  • macos安装android studio(Android Studio 2021.1.1)
    一,官网下载https://developer.android.google.cn/studio/如图:点击DownloadAndroidStudio此处选择自己电脑的芯片点击后开始下载说明:刘宏缔的架构森林是一......
  • django 自定义模板标签
    故事的背景比较复杂,框架用的django,后台用的simpleui,当我在往前端嵌入echarts的时候发现自定义标签返回的list里面的单引号进行了自动转义,变成了&#39; 具体可以参考:ht......
  • flutter Listview physics常见子类
    ListView的physics是ScrollPhysics类:其常见子类有BouncingScrollPhysics :允许滚动超出边界,但之后内容会反弹回来。ClampingScrollPhysics :防止滚动超出边界,夹住 。......
  • uView2.0 对http进行封装
    request.js://此vm参数为页面的实例,可以通过它引用vuex中的变量import{$config}from'@/config/config';module.exports=(vm)=>{//初始化请求配置uni.$......
  • 【MATLAB】matlab自定义函数的调用
    1.自定义函数的编写与调用关于自定义函数的编写与调用,将由以下3个问题展开:1.1问题:为什么要使用自定义函数?在编写程序时,我们常常会重复使用到一部分相同的代码(程序块),为了避......