美文网首页Android开发
自定义锁屏控件

自定义锁屏控件

作者: 烧饼正努力 | 来源:发表于2017-12-10 22:08 被阅读655次

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

    最近学习了一些自定义控件的知识,想着趁热多做些练习来巩固,上周自定义了一个等级进度条,是一个自定义View,这周就换一个类型,做一个自定义的ViewGroup。这周自定义ViewGroup的是一个锁屏控件,效果如下:

    效果分析:

    仔细分析效果图发现,锁屏控件需要绘制的有三个部分,分别是:

    1.图案点,图案点有四种状态,分别是默认、选中、正确和错误

    2.图案点之间的连线

    连线会根据1中点的状态改变发生颜色上的变化

    3.悬空线段

    就是图案点和悬空点之间的线段

    整体思路:

    1.自定义一个LockScreenView来表示图案点,LockScreenView有四种状态

    2.自定义一个LockScreenViewGroup,在onMeasure中获取到宽度以后(根据宽度算图案点之间的间距),动态地将LockScreenView添加进来

    3.在LockScreenViewGroup的onTouchEvent中消耗触摸事件,根据触摸点的轨迹来更新LockScreenView、图案点连线和悬空线段

    实现:

    1.自定义LockScreenView

    由于没有和这个自定义View比较类似的原生控件,因此自定义的时候直接继承自View

    首先,需要的属性通过构造函数传入:

    View的状态用一个枚举类型来表示:

    View的状态通过暴露一个方法给LockScreenViewGroup来进行设置。

    在onDraw方法中判断类型,进行绘制:

    这里在选中时用属性动画做了一个放大效果,在下次恢复正常的时候要将大小恢复回去:

    在LockScreenViewGroup中,我将LockScreenView的宽高设置为wrap_content,因此需要在onMeasure方法做一些特殊的处理,至于为什么要做特殊处理,在上一篇博文《等级进度条》中已经提到过了。

    2.自定义LockScreenViewGroup

    为了方便确定子View的位置,LockScreenViewGroup继承自RelativeLayout

    在xml中赋予了如下属性:

    其中itemCount表示一行有几个LockScreenView,其它属性都已经提到过了

    在构造函数中解析xml中的自定义属性:

    在onMeasure方法中,获取到LockScreenViewGroup的宽以后,算出LockScreenView之间的间隙,并动态地将LockScreenView添加进来(每个LockScreenView添加进来的时候,设置id作为唯一标识,后面在判断图案是否正确时会用到):

    这里有两个地方需要注意一下:

    1.LockScreenView的宽不能用getMeasuredWidth方法来获取,因为这里只是把LockScreenView创建了出来,还没有对它进行测量,故通过getMeasuredWidth方法只能得到0,这里直接把LockScreenView中大圆的直径当作它的宽(因为这里动态添加的时候用了wrap_content, 并且没有设padding)

    2.重写onMeasure方法的时候不能把super.onMeasure方法删掉,因为这里面会进行子View宽高的测量,删了子View就画不出来了

    触摸事件的消耗在onTouchEvent中处理(在这个案例中也可以在dispatchTouchEvent方法中处理,因为子View的状态由LockScreenViewGroup告诉它了,子View不需要处理触摸事件)。

    在onTouchEvent方法中对Down、Move、Up三种不同的触摸状态分别做了处理。

    (1)首先,在Down状态时,需要对之前的状态做一些重置:

    其中,mCurrentViews用来保存当前选中的LockScreenView的id,mCurrentPath用来保存图像点间线段的路径,skyStartX、skyStartY分别是悬空线段起始的x和y。

    (2)在Move状态时,判断是否在LockScreenView区域,如果在某个LockScreenView区域且这个LockScreenView之前没有被选中,则将这个LockScreenView设置为选中状态。另外在onMove中还做了图案点间线段路径和悬空线段起点和终点(mTempX、mTempY)的更新,悬空线段的起点就是上一个被选中的LockScreenView的中心点。

    (3)在Up状态时,根据答案的正确与否,对LockScreenView设置不同的状态,并且对悬空线段起始点进行重置

    在onTouchEvent方法最后会调用invalidate方法对视图进行重绘,这时会调用dispatchDraw方法进行子View的绘制。

    在dispatchDraw方法中进行图像点间的线段路径以及悬空线段的绘制:

    这里要注意,在重写dispatchDraw方法时,不能把super.dispatchDraw方法删掉,因为这里会绘制LockScreenViewGroup的子View(即,LockScreenView们),如果删了,动态添加的LockScreenView就会显示不出来(重写的时候不小心删了,排查好久才发现是这里的问题,都是泪orz)

    最后附上github源码地址:LockScreenVIew

    相关文章

      网友评论

      • 小小云_0f05:您好,请问一下怎么获取用户绘制的图案的数组?
        烧饼正努力:@小小云_0f05 每个view有一个标记,滑动时会记录到数组里,可以看下文末的代码~
      • jie啊:赞
      • 曙光_xac:我也过来支持,顺便问一下 你是怎么学的?
        曙光_xac:@烧饼正努力 好的
        烧饼正努力:@曙光_xac 自定义view的话,郭神之前有几篇基础的文章,可以去翻出来看看~主要是多看多练哈٩( 'ω' )و
      • DthFish:特地从公众号跑来点个赞!
        烧饼正努力:@DthFish 多谢支持😁

      本文标题:自定义锁屏控件

      本文链接:https://www.haomeiwen.com/subject/safbixtx.html