编程进阶网编程进阶网
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 02.Android虚拟机知识
  • 03.App核心概念分析
  • 04.Android消息机制
  • 05.Android程序UI框架
  • 06.Android应用窗口
  • 07.WMS机制深入分析
  • 08.PMS机制深入分析
  • 09.AMS机制深入分析
  • 11.四大组件原理分析
  • 12.四大组件原理分析
  • 13.View绘制流程分析
  • 14.View渲染流程分析
  • 16.Android绘制原理
  • 17.Android事件传输
  • 18.Android事件拦截
  • 21.View自定义控件反思
  • 22.ViewGroup自定义控件
  • 25.IPC跨进程通信实践
  • 29.Binder机制的理解

21.View自定义控件反思

目录介绍

  • 01.自定义控件步骤
  • 02.创建View
  • 03.测量View(Measure)
  • 04.绘制View(Draw)
  • 05.与用户进行交互
  • 06.优化自定义View

01.自定义控件步骤

  • 根据Android Developers官网的介绍,自定义控件你需要以下的步骤。(根据你的需要,某些步骤可以省略)
    • 1、创建View
    • 2、处理View的布局
    • 3、绘制View
    • 4、与用户进行交互
    • 5、优化已定义的View
  • 上面列出的五项就是android官方给出的自定义控件的步骤。
    • 每个步骤里面又包括了很多细小的知识点。可以记住这五个点,并且了解每个点里包含的小知识点。再加上一些自定义控件的练习。不断的将这些知识熟练于心,相信我们每个人都能够定义出优秀的自定义控件。接下来我们开始对上面列出的5个要点进行细化解说。

02.创建View

  • 继承View
    • 自定义的View当然也是继承于View,当然如果你要自定义的View拥有某些android已经提供的控件的功能,你可以直接继承于已经提供的控件。
  • 重写构造方法
    • Xxx(Context context)
    • Xxx(Context context, AttributeSet attrs)
    • Xxx(Context context, AttributeSet attrs, int defStyleAttr)
  • 定义自定义属性
    • 自定义属性通常写在在res/values/attrs.xml文件中。声明了自定义属性,它们都是属于styleable,一般styleable的name和我们自定义控件的类名一样。
  • 获取自定义属性
    • 当我们在 xml中创建了一个view时,所有在xml中声明的属性都会被传入到view的构造方法中的AttributeSet类型的参数当中。
    • 通过调用Context的obtainStyledAttributes()方法返回一个TypedArray对象。然后直接用TypedArray对象获取自定义属性的值。
    • 由于TypedArray对象是共享的资源,所以在获取完值之后必须要调用recycle()方法来回收。

03.测量View(Measure)

  • 测量
    • 一个View是在展示时总是有它的宽和高,测量View就是为了能够让自定义的控件能够根据各种不同的情况以合适的宽高去展示。提到测量就必须要提到onMeasure方法了。onMeasure方法是一个view确定它的宽高的地方。
  • 下面是一个重写onMeasure的固定伪代码写法:
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measureWidth = measure(widthMeasureSpec, true);
        int measureHeight = measure(heightMeasureSpec, false);
        setMeasuredDimension(measureWidth, measureHeight);
    }
    • 计算出height和width之后在onMeasure中别忘记调用setMeasuredDimension()方法。否则会出现运行时异常。
  • 计算一些自定义控件需要的值 onSizeChange()
    • onSizeChange() 方法在view第一次被指定了大小值、或者view的大小发生改变时会被调用。所以一般用来计算一些位置和与view的size有关的值。

04.绘制View(Draw)

  • 一旦自定义控件被创建并且测量代码写好之后,接下来你就可以实现onDraw()来绘制View。
    • onDraw方法包含了一个Canvas叫做画布的参数,onDraw()简单来说就两点:Canvas决定要去画什么;Paint决定怎么画
    • 比如,Canvas提供了画线方法,Paint就来决定线的颜色。Canvas提供了画矩形,Paint又可以决定让矩形是空心还是实心。
  • 在onDraw方法中开始绘制之前
    • 你应该让画笔Paint对象的信息初始化完毕。这是因为View的重新绘制是比较频繁的,这就可能多次调用onDraw,所以初始化的代码不应该放在onDraw方法里。
  • Paint画笔
    • 在绘图过程中起到了极其重要的作用,画笔主要保存了颜色,样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。
  • Canvas画布
    • 当调整好画笔之后,需要绘制到画布上,这就得用Canvas类。Canvas画布可以绘制任何东西。除了在画布上绘制之外,还需要设置一些关于画布的属性,比如,画布的颜色、尺寸等。
  • 常见绘制操作有哪些
    • drawRect,drawRoundRect,绘制矩形
    • drawOval,drawCircle,drawArc:绘制椭圆,圆,以及圆弧
    • drawText:绘制文本
    • drawBitmap:绘制图片
  • Rect和RectF介绍和却别
    • Rect的参数为int类型,而RectF的参数类型为float类型,从这一点上来看,RectF的精度更高一些,但是他们都是通过四个坐标参数来确定一个矩形的区域。

05.与用户进行交互

  • 也许某些情况你的自定义控件不仅仅只是展示一个漂亮的内容,还需要支持用户点击,拖动。这时候自定义控件就需要做用户交互这一步骤了。
  • 在Android系统中最常见的事件就是触摸事件了,它会调用view的onTouchEvent(android.view.MotionEvent).重写这个方法去处理我们的事件逻辑。
  • 现在的触控有了更多的手势,比如轻点,快速滑动等等,所以在支持特殊用户交互的时候你需要用到android提供的GestureDetector.你只需要实现GestureDetector中相对应的接口,并且处理相应的回调方法。
  • 除了手势之外,如果有移动之类的情况我们还需要让滑动的动画显示得比较平滑。动画应该是平滑的开始和结束,而不是突然消失突然开始。在这种情况下,我们需要用到属性动画 property animation framework

06.优化自定义View

  • 在上面的步骤结束之后,其实一个完善的自定义控件已经出来了。接下来你要做的只是确保自定义控件运行得流畅,官方的说法是:为了避免你的控件看得来迟缓,确保动画始终保持每秒60帧。
  • 下面是官网给出的优化建议:
    • 1、避免不必要的代码
    • 2、在onDraw()方法中不应该有会导致垃圾回收的代码。
    • 3、尽可能少让onDraw()方法调用,大多数onDraw()方法调用都是手动调用了invalidate()的结果,所以如果不是必须,不要调用invalidate()方法。
贡献者: yangchong211
上一篇
18.Android事件拦截
下一篇
22.ViewGroup自定义控件