Android自定义view绘制顺序

onDraw

之前我们自定义view一般都继承了View这个类,其实Android里面所有的控件也都继承自这个类,无论是一个view还是viewGroup了,最终都是继承自view。好,如果我们自定义view直接继承自View类,那么我们重写了onDraw在里面做一些自己的绘制,我们也会重写super.onDraw(canvas),但是点击进去看会发现是空实现,只是用注释告诉我们“Implement this to do your drawing”,所以如果是继承自view,那么其实这个super是完全可以不写的,因为父类是空实现啊,但是如果是继承一个现有的view呢,那就不用点击过去看,肯定不是空实现,因为现有控件的绘制操作也是在onDraw里面写的啊,所以这个时候自己把代码写在super.onDraw(canvas)前面还是后面是有影响的

    把自己绘制的代码写在super.onDraw的后面,由于绘制代码会在原有内容绘制结束之后执行,所以绘制内容就会盖住控件原来的内容(这种应用场景就比较多,好比在原来的基础上面加一些东西)
    把自己绘制的代码写在super.onDraw的前面,由于绘制代码会在原有内容绘制之前执行,所以绘制的内容会被控件的super.onDraw的内容覆盖(这种应用场景比较少,但是也会有,例如给继承自textview的文本绘制一个背景色啦,当然绘制背景色有更简单的方法)

dispatchDraw

上面的onDraw是针对view自身的绘制,但是如果是把一个view放在viewGroup里面呢?那么父view和子view的绘制顺序又要怎么把握呢?就需要在这个dispatchDraw方法上面做文章了,先来看看这个方法的注释“Called by draw to draw the child views. This may be overridden by derived classes to gain control just before its children are drawn (but after its own view has been drawn).”翻译一下就是这个方法被draw方法调度然后绘制子view,这个方法可以被重写来获得控制权,以能够在它的子view们被绘制之前来做一些事情,但是此时它自身已经被绘制完毕了。好比有这么个例子,我们自定义了一个view继承自linearlayout,是的是一个viewgroup,然后我们想给linearlayout添加一些圆圈的幻影,然后我们将这个linearlayout写在xml中,如果它没有任何子view,那么这个幻影能够正常的展示出来,但是如果我们给这个linearlayout添加了子view,就会发现原来有的幻影现在没有了,这是因为幻影被子view遮盖了,那么要怎么处理呢?其实也很简单,就是在绘制完子view之后我们再绘制linearlayout的幻影就好了,这样就解决问题了,而上面的注释也说了,dispatchDraw方法就是用来调度绘制子view的方法,那么我们把绘制幻影的代码写在super.dispatchDraw(canvas);之后就好了,就这么简单
关于绘制的顺序概述

    背景background的绘制,这个是发生在一个drawBackground(Canvas canvas)的private的私有方法里面,所以我们无法重写这个方法,只能通过现有Android提供的API去设置它
    onDraw主体绘制,如果是对于父布局而言,也是先调用onDraw绘制自己,然后调用dispatchDraw去绘制子view
    dispatchDraw绘制子view
    滑动边缘渐变和滑动条
    前景(foreGround)(前景的支持是从Android6.0开始的,之前的只是支持framelayout),但是我们貌似一般都不用。这个是被放在一个onDrawForeground方法里面的, 该方法是可以被重写的,做一些自己的设置。当然也可以利用API自带的方法通过xml中的android:scrollbarXXX系列属性设置或者在java代码中调用对应的set方法来进行设置。如果重写了这个那么在super.onDrawForeground()方法的前后写代码则可以控制绘制内容和和滑动边缘以及前景的遮盖关系

关于绘制方法的调度概述

为什么上面的方法会按照那样的如下的顺序:背景—onDraw—dispatchDraw—滑动边缘渐变和滑动条—foreGround的顺序来绘制呢?这是因为有一个方法在进行总调度,它就是draw方法,所以如果想要在所有的绘制之前或者所有绘制方法都调用完成后做一些事情,那么就可以重写这个draw方法了,所以如果将自己的绘制代码写在了super.draw(canvas);前面,那么相当于自己绘制的代码会被所有后面的绘制覆盖,如果写在了super.draw(canvas);后面,那么相当于自己的绘制代码会覆盖所有后面的绘制,其实将代码写在super.draw(canvas)后面相当于将代码写在了super.onDrawForeground后面了,因为执行到onDrawForeground就已经执行到绘制的结束时候了
关于绘制代码书写位置的概述

    出于效率考虑,viewgroup默认会绕过draw,onDraw方法,换而直接执行dispatchdraw,以此来简化绘制流程,所以如果你自定义了某个 ViewGroup 的子类(比如 LinearLayout)并且需要在它的除 dispatchDraw() 以外的任何一个绘制方法内绘制内容,你可能会需要调用 View.setWillNotDraw(false) 这行代码来切换到完整的绘制流程
    有时候代码写在ondraw里面可以,也可以写在dispatchDraw,但是推荐写在onDraw里面,因为对于这个方法android有优化,可以在不需要重绘时候自动跳过onDraw避免重复执行



转自原文:https://blog.csdn.net/submit66/article/details/80112287
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值