• 自定义 View 绘制顺序 HenCoder-5 [MD]


    博文地址

    我的GitHub 我的博客 我的微信 我的邮箱
    baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

    目录

    扔物线自定义 View 系列教程总结-5

    全文整理自 扔物线(HenCoder)自定义 View 系列文章

    重新整理的目标:

    • 内容压缩:去除活跃气氛的段子、图片,去除无意义的解释、代码,去除不刚兴趣的内容,压缩比至少 50%
    • 排版优化:更清晰的结构,更精简的标题,更规范的缩进、标点符号、代码格式,好的结构才能更好的吸收
    • MarkDown:以标准的 MarkDown 格式重新编排,纯文本更易迭代维护

    扔物线自定义 View 系列教程分绘制布局触摸反馈三部分内容。

    绘制顺序

    总结

    Android 里面的绘制都是按顺序的,先绘制的内容会被后绘制的盖住,所以控制好绘制顺序是非常重要的。

    一个完整的绘制过程会依次绘制以下几个内容:

    • 绘制背景drawBackground()
    • 绘制主体onDraw()
    • 绘制子 ViewdispatchDraw()
    • 绘制滑动边缘渐变和滑动条以及前景onDrawForeground()

    drawBackground 绘制背景

    这个方法是 private 的,不能重写,也就是说不能自定义绘制。可以通过android:background属性或View.setBackgroundXxx()方法设置背景。

    onDraw 绘制主体

    onDraw() 是负责自身主体内容绘制的。在 View 中,onDraw() 是空实现,所以直接继承 View 的类,它们的 super.onDraw() 什么也不会做。

    写在 super.onDraw 下面

    绘制内容就会盖住控件原来的内容,可以为控件增加点缀性内容。

    在 Debug 模式下绘制出 ImageView 的图像尺寸信息:

    写在 super.onDraw 上面

    绘制的内容会被控件的原内容盖住,这种用法的场景相对来说会少一些。

    通过在文字的下层绘制纯色矩形来作为「强调色」:

    dispatchDraw 绘制子 View

    在绘制过程中,每个 View 和 ViewGroup 都会先调用 onDraw() 方法来绘制主体,再调用 dispatchDraw() 方法来绘制子 View。

    如果你继承了一个 LinearLayout,重写了它的 onDraw() 方法,在 super.onDraw() 后插入了你自己的绘制代码,以便使它能够在内部绘制一些斑点作为点缀。但是你会发现,当你添加了子 View 之后,你的斑点不见了。造成这种情况的原因是:在绘制过程中,每一个 ViewGroup 会先调用自己的 onDraw() 来绘制完自己的主体之后再去绘制它的子 View,那么在子 View 绘制完成之后,先前绘制的斑点就被子 View 盖住了。

    注:由于 View 没有子 View,所以一般来说这个方法只对 ViewGroup 有意义。

    写在 super.dispatchDraw 下面

    绘制的内容发生在子 View 的绘制之后,所以绘制内容会盖住子 View

    上面说的 LinearLayout 案例,就应该放在 super.dispatchDraw 下面

    写在 super.dispatchDraw 上面

    这其实和前面讲的把绘制代码写在 super.onDraw() 之后的效果是一样的。

    onDrawForeground 绘制前景

    • Android 6.0(API 23)之前,仅FrameLayout支持前景,6.0 后所有View都支持
    • 滑动边缘渐变和滑动条可以通过android:scrollbarXXX系列属性或View.setXXXScrollbarXXX()系列方法来设置
    • 前景可以通过android:foreground属性或View.setForeground()方法来设置

    虽然这三部分是依次绘制的,但它们被一起写进了这个方法里,所以不能在它们之间插入自定义绘制

    写在 super.onDrawForeground 下面

    绘制代码会在滑动边缘渐变、滑动条和前景之后被执行,所以绘制内容会盖住滑动边缘渐变、滑动条和前景

    在 ImageView 左上角添加「New」标签,要求不能被遮罩(foreground)盖住

    写在 super.onDrawForeground 上面

    这种写法,和前面讲的把绘制代码写在 super.dispatchDraw() 的下面的效果是一样的。

    在 ImageView 左上角添加「New」标签,要求需要被遮罩(foreground)盖住

    draw 总调度方法

    draw() 是绘制过程的总调度方法,一个 View 的整个绘制过程都发生在 draw() 方法里。前面讲到的背景、主体、子 View 、滑动相关以及前景的绘制,它们其实都是在 draw() 方法里调用的。

    // View.java 的 draw() 方法的简化版大致结构
    public void draw(Canvas canvas) {
        drawBackground(Canvas); // 绘制背景(不能重写)
        onDraw(Canvas); // 绘制主体
        dispatchDraw(Canvas); // 绘制子 View
        onDrawForeground(Canvas); // 绘制滑动相关和前景
    }
    

    所以也可以通过重写 draw() 方法来做自定义的绘制。

    写在 super.draw 下面

    绘制的内容会在其他所有绘制完成之后再执行,也就是说,它的绘制内容会盖住其他的所有绘制内容

    它的效果和把绘制代码写在 super.onDrawForeground() 下面时的效果是一样的,都会盖住其他的所有内容。

    写在 super.draw 上面

    绘制的内容会在其他所有绘制之前被执行,所以这部分绘制内容会被其他所有的内容盖住,包括背景。

    是不是觉得没用?觉得怎么可能会有谁想要在背景的下面绘制内容?别这么想,有的时候它还真的有用。

    例如 EditText,它下面的那条横线是它的背景(background)

    如果我想给这个 EditText 加一个绿色的底,我不能使用给它设置绿色背景色android:background="#66BB6A"的方式,因为这就相当于是把它的背景替换掉,从而会导致下面的那条横线消失

    在这种时候,你就可以重写它的 draw() 方法,然后在 super.draw() 的上方插入代码,以此来在所有内容的底部涂上一片绿色:

    public void draw(Canvas canvas) {
        canvas.drawColor(Color.parseColor("#66BB6A")); // 涂上绿色
        super.draw(canvas);
    }
    

    注意事项

    关于绘制方法,有两点需要注意:

    1、在 ViewGroup 的子类中重写除 dispatchDraw() 以外的绘制方法时,可能需要调用 setWillNotDraw(false)

    出于效率的考虑, ViewGroup 默认会绕过 draw() 方法,换而直接执行 dispatchDraw(),以此来简化绘制流程。所以如果你自定义了某个 ViewGroup 的子类并且需要在它的除 dispatchDraw() 以外的任何一个绘制方法内绘制内容,你 可能 会需要调用 View.setWillNotDraw(false) 这行代码来切换到完整的绘制流程。是「可能」而不是「必须」的原因是,有些 ViewGroup 是已经调用过 setWillNotDraw(false) 了的,例如 ScrollView

    2、在重写的方法有多个选择时,优先选择 onDraw()

    一般情况,一段绘制代码写在不同的绘制方法中效果是一样的,但有一个例外:如果绘制代码既可以写在 onDraw() 里,也可以写在其他绘制方法里,那么优先写在 onDraw()。因为 Android 有相关的优化,可以在不需要重绘的时候自动跳过 onDraw() 的重复执行,以提升开发效率。享受这种优化的只有 onDraw() 一个方法。

    2021-5-7

  • 相关阅读:
    jmeter 安装
    Day05_系统监控、rpm、yum软件包管理及源码安装python解释器
    Day04_vim编辑器及硬盘操作
    Day03_用户群组权限及正文处理命令
    Day02_操作系统、网络及Linux基础
    Day01_计算机硬件及启动流程
    让Sublime Text成为静态WEB服务器:SublimeServer
    sublime text2-text3 定义的不同浏览器的预览快捷键
    css之px自动转rem—“懒人”必备
    修改Sublime Text3 的侧边栏字体大小
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/14743101.html
Copyright © 2020-2023  润新知