当前位置:首页 > 谈天说地

Android自定义View实现时钟功能

34资源网2022-09-13350

最近在练习自定义view, 想起之前面试的时候笔试有道题是写出自定义一个时钟的关键代码. 今天就来实现一下. 步骤依然是先分析, 再上代码.

实现效果

view分析

时钟主要分为五个部分:

1、中心点: 圆心位置

2、圆盘: 以中心点为圆心,drawcircle画个圆

3、刻度:

paint有个aip, setpatheffect可以根据path画特效, 那么刻度就可以根据圆的path画一个矩形path的特效, 并且这个api只会画特效, 不会画出圆.

/**
* shape: 特效的path, 这里传一个矩形
* advance: 两个特效path之间的间距, 即两个矩形的left间距
* phase: 特效起始位置的偏移
* style: 原始path拐弯的时候特效path的转换方式,这里用rotate跟着旋转即可
*/
pathdashpatheffect(path shape, float advance, float phase,
                              style style)

刻度又分两种, 粗一点刻度: 3、6、9、12, 和细一点的刻度. 两种特效又可以用sumpatheffect合起来画

sumpatheffect(patheffect first, patheffect second) 

4、时分秒指针

时分秒指针都是一个圆角矩形, 先把他们的位置计算出来, 然后旋转圆心去绘制不同角度的指针.

5、动画效果

timertask每隔一秒计算时间, 根据时间去换算当前时分秒指针的角度, 动态变量只有三个角度.

实现源码

//
// created by skylar on 2022/4/19.
//
class clockview : view {
    private var mtimer: timer? = null
    private val mcirclepaint: paint = paint()
    private val mpointerpaint: paint = paint()
    private val mtextpaint: paint = paint()

    private val mcirclepath: path = path()
    private val mhourpath: path = path()
    private val mminutepath: path = path()
    private val msecondpath: path = path()

    private lateinit var mpathmeasure: pathmeasure
    private lateinit var msumpatheffect: sumpatheffect

    private var mviewwidth = 0
    private var mviewheight = 0
    private var mcirclewidth = 6f
    private var mradius = 0f
    private var mrectradius = 20f
    private var mhoursdegree = 0f
    private var mminutesdegree = 0f
    private var msecondsdegree = 0f
    private var mcurrenttimeinsecond = 0l

    constructor(context: context) : super(context)

    constructor(context: context, attrs: attributeset?) : this(context, attrs, 0)

    constructor(
        context: context, attrs: attributeset?,
        defstyleattr: int
    ) : super(context, attrs, defstyleattr)

    init {
        mcirclepaint.color = color.black
        mcirclepaint.isantialias = true
        mcirclepaint.style = paint.style.stroke
        mcirclepaint.strokewidth = mcirclewidth

        mpointerpaint.color = color.black
        mpointerpaint.isantialias = true
        mpointerpaint.style = paint.style.fill

        mtextpaint.color = color.black
        mtextpaint.isantialias = true
        mtextpaint.style = paint.style.fill
        mtextpaint.textsize = 40f
    }

    override fun onsizechanged(w: int, h: int, oldw: int, oldh: int) {
        super.onsizechanged(w, h, oldw, oldh)
        mviewwidth = measuredwidth - paddingleft - paddingright
        mviewheight = measuredheight - paddingtop - paddingbottom

        mradius = mviewwidth / 2 - mcirclewidth
        mcirclepath.addcircle(0f, 0f, mradius, path.direction.cw)

        mpathmeasure = pathmeasure(mcirclepath, false)
        val minutesshapepath = path()
        val quartershapepath = path()
        minutesshapepath.addrect(0f, 0f, mradius * 0.01f, mradius * 0.06f, path.direction.cw)
        quartershapepath.addrect(0f, 0f, mradius * 0.02f, mradius * 0.06f, path.direction.cw)
        val minutesdashpatheffect = pathdashpatheffect(
            minutesshapepath,
            mpathmeasure.length / 60,
            0f,
            pathdashpatheffect.style.rotate
        )
        val quarterdashpatheffect = pathdashpatheffect(
            quartershapepath,
            mpathmeasure.length / 12,
            0f,
            pathdashpatheffect.style.rotate
        )
        msumpatheffect = sumpatheffect(minutesdashpatheffect, quarterdashpatheffect)

        val hourpointerheight = mradius * 0.5f
        val hourpointerwidth = mradius * 0.07f
        val hourrect = rectf(
            -hourpointerwidth / 2,
            -hourpointerheight * 0.7f,
            hourpointerwidth / 2,
            hourpointerheight * 0.3f
        )
        mhourpath.addroundrect(hourrect, mrectradius, mrectradius, path.direction.cw)

        val minutepointerheight = mradius * 0.7f
        val minutepointerwidth = mradius * 0.05f
        val minuterect = rectf(
            -minutepointerwidth / 2,
            -minutepointerheight * 0.8f,
            minutepointerwidth / 2,
            minutepointerheight * 0.2f
        )
        mminutepath.addroundrect(minuterect, mrectradius, mrectradius, path.direction.cw)

        val secondpointerheight = mradius * 0.9f
        val secondpointerwidth = mradius * 0.03f
        val secondrect = rectf(
            -secondpointerwidth / 2,
            -secondpointerheight * 0.8f,
            secondpointerwidth / 2,
            secondpointerheight * 0.2f
        )
        msecondpath.addroundrect(secondrect, mrectradius, mrectradius, path.direction.cw)

        startanimator()
    }

    override fun ondraw(canvas: canvas?) {
        super.ondraw(canvas)
        if (canvas == null) {
            return
        }
        canvas.translate((mviewwidth / 2).tofloat(), (mviewheight / 2).tofloat())

        //画圆盘
        mcirclepaint.patheffect = null
        canvas.drawpath(mcirclepath, mcirclepaint)

        //画刻度
        mcirclepaint.patheffect = msumpatheffect
        canvas.drawpath(mcirclepath, mcirclepaint)

        //时分秒指针
        mpointerpaint.color = color.black

        canvas.save()
        canvas.rotate(mhoursdegree)
        canvas.drawpath(mhourpath, mpointerpaint)
        canvas.restore()

        canvas.save()
        canvas.rotate(mminutesdegree)
        canvas.drawpath(mminutepath, mpointerpaint)
        canvas.restore()

        canvas.save()
        canvas.rotate(msecondsdegree)
        canvas.drawpath(msecondpath, mpointerpaint)
        canvas.restore()

        //画中心点
        mpointerpaint.color = color.white
        canvas.drawcircle(0f, 0f, mradius * 0.02f, mpointerpaint)
    }


    private fun startanimator() {
        val cal = calendar.getinstance()
        val hour = cal.get(calendar.hour)  //小时
        val minute = cal.get(calendar.minute)  //分
        val second = cal.get(calendar.second)  //秒
        mcurrenttimeinsecond = (hour * 60 * 60 + minute * 60 + second).tolong()

        if (mtimer == null) {
            mtimer = timer()
        } else {
            mtimer?.cancel()
            mtimertask.cancel()
        }
        mtimer?.schedule(mtimertask, 0, 1000)
    }

    private var mtimertask: timertask = object : timertask() {
        override fun run() {
            mcurrenttimeinsecond++
            computedegree()
            invalidate()
        }
    }

    //12小时 00:00:00 ~ 12:00:00
    private fun computedegree() {
        val secondsinoneroll = 12 * 60 * 60
        val currentseconds = mcurrenttimeinsecond % secondsinoneroll

        var leftseconds = currentseconds
        val hours = currentseconds / 60 / 60
        leftseconds = currentseconds - hours * 60 * 60
        val minutes = leftseconds / 60
        leftseconds -= minutes * 60
        val seconds = leftseconds % 60

        mhoursdegree = hours * 30f
        mminutesdegree = minutes * 6f
        msecondsdegree = seconds * 6f

    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持萬仟网。

看完文章,还可以扫描下面的二维码下载快手极速版领4元红包

快手极速版二维码

快手极速版新人见面礼

除了扫码领红包之外,大家还可以在快手极速版做签到,看视频,做任务,参与抽奖,邀请好友赚钱)。

邀请两个好友奖最高196元,如下图所示:

快手极速版邀请好友奖励

扫描二维码推送至手机访问。

版权声明:本文由34楼发布,如需转载请注明出处。

本文链接:https://www.34l.com/post/22062.html

分享给朋友:

相关文章

100句关于老祖宗留下来的话,都是经典名言

100句关于老祖宗留下来的话,都是经典名言

在浩瀚的历史文化中,我们的祖先除了给我们留下了很多的精神财富和文化遗产,像下面这100句老祖宗留下来的经典名言,我们一定要好好了解下。…

​京东钢镚怎么使用?教你用京东钢镚的支付的方法教程

​京东钢镚怎么使用?教你用京东钢镚的支付的方法教程

京东钢镚怎么使用?很多朋友看到自己的京东钱包里面有京东钢镚,不知道京东钢镚怎么使用,在使用京东钢镚之前,一定要要先了解清楚京东钢镚使用条件有哪些,下面开淘小编来介绍一下京东钢镚怎么使用?如何用你的京东钢镚支付购买商品的方法教程分享。…

调整心态温暖哲理经典语录,看这些语录能够调整心态

调整心态温暖哲理经典语录,看这些语录能够调整心态

取得成功是他人不成功时仍在坚持不懈。若自身不作出一点外貌,别人想拉你一把都不知道你的手在哪儿。直至你不会再找我聊,直至你找不着我,直至最终,你一直在某一瞬间猛地想起我。但是,那个时候,被你弄丢的我就确实早已没有了,也再不想要你再找回家了。理…

抖音长视频怎么开通?抖音开通长视频的权限分享

抖音长视频怎么开通?抖音开通长视频的权限分享

经常玩抖音的朋友来说开通抖音1分钟长视频已经不是一件难事了。大家都知道抖音默认视频长度为15秒。只有达到一定要求才可以获得长视频权限。但是现在我们发现能发抖音长视频的朋友越来越多了。他们是怎么做到的呢?抖音怎么发长1分钟视频呢?抖音长视频是…

融资丨「PPIO边缘云」完成亿元A1轮融资,刷新边缘云领域融资记录

融资丨「PPIO边缘云」完成亿元A1轮融资,刷新边缘云领域融资记录

创业邦获悉,近日,边缘云公司PPIO宣布完成过亿元A1轮融资,由创世伙伴、张江科投、磐霖资本等多家机构联合投资,Pre-A轮投资方蓝驰创投、沸点资本及华业天成继续追加投资,光源资本担任融资财务顾问。这是公司半年内再次获投资人支持,公司A2轮…

融资丨「奕斯伟计算」完成25亿元C轮融资,目标物联网芯片领域全球领导者

融资丨「奕斯伟计算」完成25亿元C轮融资,目标物联网芯片领域全球领导者

创业邦获悉,12月1日,AIoT芯片与解决方案提供商北京奕斯伟计算技术有限公司(以下简称:奕斯伟计算)宣布完成25亿元人民币C轮融资,由金石投资和中国互联网投资基金联合领投,尚颀投资、国开科创、华新投资等跟投,老股东 IDG、君联资本、刘益…