Android 自定义view 基础篇(二)

目录

从0到1Android自定义View(二) 分类和核心函数.png

一、自定义 View 分类

常见的 Android 自定义 View 主要有两种类型:

1、组合控件

通过 Android 的基础控件(TextView、ImageView、Button、ProgressBar 等)组合而成,比如下拉刷新、瀑布流控件、带左/右滑功能的控件、视频控件等,这种自定义View的难点在于程序的逻辑处理

2、完全自定义控件

继承自 View、TextureView 或 SurfaceView ,然后重写核心的回调方法,以View 为例,按需复写其构造、onMeasure、onLayout、onTouchEvent、onDraw、onAttachedToWindow、onDetachedFromWindow 等方法,这种自定义 View 的难点在于程序的设计、效率优化和排版,比如输入法中的手写控件、图文混排控件(现在很多都是通过webview加载网页实现了)、个性化进度条、弹幕显示控件、Markdown控件、IDE代码编辑控件等

注意:

我们需要合理的使用自定义 View ,千万不能滥用,不要动不动就自定义 View ,基础控件能完成的功能,千万别自定义 View,因为基础空间 Android,本身就有性能优化的,自定义 View 的价值在于做到基础控件无法做到的效果,为应用的表现增色;,将公用的交互效果提取成自定义控件,方便复用,减少不必要的重复劳动。

二、自定义 View 核心知识点

这部分主要是介绍自定义 View 的核心知识点,上面提到过,完全自定义 View 通常是继承 View ,TextureView,SurfaceView,所以先来了解下这三者之间的区别所在。

1、 View、SurfaceView、TextureView 的区别

View

普通的 View,与宿主窗口共享同一个绘图表面,UI 在主线程中绘制,在有无硬件加速的情况下都能工作(没有硬件加速的情况下,canvas 的有些方法会失效)

SurfaceView

继承自 View,绘制和显示效率高,因为拥有独立的绘图表面,UI 在一个独立的线程中进行绘制,不会占用主线程的资源。SurfaceView 的使用和普通的 View 不一样,需要结合 SurfaceHodler 一起使用。因为和宿主窗口不是共享同一个绘图表面的原因,对其做动画操作可能会得不到想要的效果

TextureView

继承自 View,与 SurfaceView 相比,TextureView 不会创建一个单独的绘图表面,这使得它可以像一般的 View 一样执行一些变换操作,比如移动、动画等等,但 TextureView 必须在硬件加速开启的窗口中才能正常工作;

2、 几个重要的函数

最后通过自定义 View 的流程图来了解一下自定义 View 几个重要的函数。

自定义view的流程图.jpg

(1)构造函数

构造函数是View的入口,可以用于初始化一些的内容,和获取自定义属性

View的构造函数有四种重载

自定义View的构造函数.png

从上面的图也可以看出,自定 View 的构造函数的参数最多有四个,而且有四个参数的构造函数只能在 API 21 以上使用,因此四个参数的构造函数先不考虑,不过我们也需要了解这四个参数具体代表什么?

Context:View 中随处都会用到

AttributeSet:XML 属性(从 XML inflate 的时候使用)

int defStyleAttr:应用到 View 的默认风格(定义在主题中)

int defStyleRes:如果没有使用 defStyleAttr,应用到 View 的默认风格

那么这里就有个问题了,有四种构造函数,我们该怎么选择呢?

比如上面图片显示的自定义的 MyView ,继承 View 对象,如果我们想在普通的代码中新建一个 MyView,可以直接使用一个参数的构造函数,这也是大多数选择使用的。

一个参数的构造函数.png

那么两个参数的构造函数什么时候使用呢?比如有时候在 xml 中添加一个自定义 View ,并且加了一些布局属性,宽高属性以及 margin 属性,这些属性会存放在第二个构造函数的 AttributeSet 参数里。

两个参数的构造函数.png

有三个参数的构造函数比第二个构造函数多了一个 int 型的值,名字叫 defStyleAttr ,从名称上判断,这是一个关于自定义属性的参数。第三个构造函数不会被系统默认调用,而是需要我们自己去显式调用,比如在第二个构造函数里调用调用第三个函数,并将第三个参数设为0 。defStyleAttr 指定的是在Theme style 定义的一个 attr,它的类型是 reference 主要生效在 obtainStyledAttributes 方法里,obtainStyledAttributes 方法有四个参数,第三个参数是 defStyleAttr ,第四个参数是自己指定的一个 style ,当且仅当 defStyleAttr 为 0 或者在 Theme 中找不到 defStyleAttr 指定的属性时,第四个参数才会生效,这些指的都是默认属性,当在 xml 里面定义的,就以在 xml 文件里指定的为准,所以优先级大概是:xml>style>defStyleAttr>defStyleRes>Theme 指定,当defStyleAttr 为 0 时,就跳过 defStyleAttr 指定的 reference ,所以一般用 0 就能满足一些基本开发。

(2)onMeasure(测量 View 大小)

这个函数有什么用呢?将这个问题转化一下,就是问为什么要测量 View 的大小呢?

因为 View 的大小不仅由自身所决定,同时也会受到父控件的影响,为了我们的控件能更好的适应各种情况,一般会自己进行测量

onMeasure.png

MeasureSpce 的 mode 有三种:EXACTLY, AT_MOST,UNSPECIFIED,除去 UNSPECIFIED 不谈,其他两种 mode:

当父布局是 EXACTLY 时,子控件确定大小或者 match_parent,mode 都是 EXACTLY,子控件是 wrap_content 时,mode 为 AT_MOST;

当父布局是 AT_MOST 时,子控件确定大小,mode 为 EXACTLY,子控件 wrap_content 或者 match_parent 时,mode 为 AT_MOST。

所以在确定控件大小时,需要判断 MeasureSpec 的 mode,不能直接用 MeasureSpec 的 size。在进行一些逻辑处理以后,调用 setMeasureDimension() 方法,将测量得到的宽高传进去供 layout 使用。

onMeasure流程.png

在实际运用之中只需要记住有测量模式有三种,用 MeasureSpec 的 getSize是获取数值, getMode是获取模式即可。如果对 View 的宽高进行修改了,不要调用 super.onMeasure( widthMeasureSpec, heightMeasureSpec); 要调用 setMeasuredDimension( widthsize, heightsize); 这个函数。

(3)onSizeChanged(确定 View 大小)

那么这个函数又是什么时候调用呢?

这个函数在视图大小发生改变时调用。

那么问题又来了,上面的 onMeasure 函数中不是说对 View 的宽高进行了修改后,要调用 setMeasuredDimension 吗?调用这个方法后,View 的大小基本已经确定了啊,View 的视图大小还会发生变化吗?这是因为 View 的大小不仅仅只是由其本身来决定的,也受它的父控件影响,所以在确定 View 大小的时候最好使用系统提供的 onSizeChanged 回调函数。

onSizeChanged.png

(4)onLayout(确定子 View 布局位置)

确定布局的函数是 onLayout ,它用于确定子 View 的位置,在自定义 ViewGroup 中会用到,他调用的是子 View 的 layout 函数。比如,有时候我们自定义 View 的时候,需要获取 View 的一些信息就需要用到这个函数。当然,如果是单纯的 View 就没与必要重写这个方法,为什么这么说呢?

因为单纯的 View ,不是一个 View 容器,没有子 View ,而 onLayout 方法里主要是具体摆放子View 的位置,水平摆放或者垂直摆放,所以在单纯的自定义 View 是不需要重写 onLayout 方法。不过需要注意的一点是,子 View 的 margin 属性是否生效就要看 parent 是否在自身的 onLayout 方法进行处理,而 View 的 padding 属性是在 onDraw 方法中生效的

(5)onDraw(绘制内容)

重头戏,onDraw,也就是是实际绘制的部分。

onDraw.png

一般自定义控件耗费心思最多的就是这个方法了,需要在这个方法里,用 Paint 在 Canvas 上画出你想要的图案。如果是直接继承的 View,那么在重写 onDraw 的方法是时候完全可以把 super.ondraw(canvas) 删掉,因为它的默认实现是空。

注:非原创,不装逼,不虚假。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容