PS:本文系转载文章,阅读原文可读性会更好,文章末尾有原文链接
ps:本文是基于 Android API 31 来分析的,文章写的 demo 是用 AndroidStudio 工具来开发的。
目录
1、自定义 View 的分类
2、自定义 View 的注意事项
3、自定义 View 的实例
1、自定义 View 的分类
自定义 View 的分类到目前还没有统一的标准,以我对自定义 View 的学习积累,我把自定义 View 规划为以下这4类。
(1)直接继承于 View
直接继承于 View 来绘制一些不规则的视图,需要通过绘制的方式来实现,也就是要重写 View 的 onDraw方法;直接继承于 View 的子类都是需要自己去处理 wrap_content (看Android中View的工作流程之measure过程这篇文章,如果自定义的 View 直接继承 View 不处理 wrap_content,那么就和 match_parent 的效果是一样的)和 padding ,否则做出来的效果和我们实现的不一样。
(2)直接继承于 ViewGroup
这种方法用于实现自定义的布局,像 LinearLayout、RelativeLayout 等是属于系统的布局,如果我们需要重新定义一种新布局,可以采用这种方法来实现,比如说布局可以左右(把ViewPager看作是一种自定义布局嘛)且还产生水波纹效果的时候,用这种方式有点复杂,需要适当地处理 ViewGroup 的测量、布局这两个过程,与此同时处理子元素的测量和布局过程。
(3)直接继承于具体的 View(例如 TextView)
用于拓展某种已具有的 View 功能,比如说 TextView,它被 Button 继承着,Button 主要用来设置点击事情的;直接继承于具体的 View,它不需要自己去处理 wrap_content 和 padding。
(4)直接继承于具体的 ViewGroup(例如 FrameLayout)
如果某种效果看起来和具体的 ViewGroup 很像的时候,也就是和具体的 ViewGroup 布局子元素特性很像的时候,可以采用这种方法来实现,采用这种方法不需要自己处理 ViewGroup的 measure 和 layout 这两个过程。
一种 View 的显示效果有很多种自定义 View 的方式去实现,喜欢用哪种最终还是看开发者自己的喜好,好,我们现在说一下自定义 View 应该注意的一些事项。
2、自定义 View 的注意事项
(1)直接继承于 View 或者 ViewGroup,当用到 wrap_content 值时,必须支持 wrap_content;如果不在 onMeasure 中对 wrap_content 做特殊处理,那么当自定义 View 或者自定义 ViewGroup 在布局中使用 wrap_content 时就没法达到预期的效果,那么我们看到的就是和 match_parent 一样的效果,可以看Android中View的工作流程之measure过程这篇文章,你们就可以看到和 match_parent 一样的效果了。
(2)如果直接继承 View 且使用到 padding 时,如果不在 draw 方法中处理 padding,那么 padding 属性就不会起作用;如果直接继承自 ViewGroup 并且使用到 wrap_content 时,需要在 onMeasure 和 onLayout 方法中处理 padding 和子 View 的 margin 对它造成的影响。
(3)不要在自定义 View 中创建一个 Handler ,因为 View 提供了 post 一系列的方法,View 的一系列 post 方法其实还是调用了 Handler 的 post 一系列的方法。
(4)当 View 变得不可见时我们需要停止线程和动画,如果不处理这种情况,很容易造成内存泄漏;如果有线程或者动画需要停止时,最好是在 View 的 onDetachedFromWindow 方法中进行调用,因为 Activity 退出或者 View 被删除的时候,View 的 onDetachedFromWindow 方法会被执行。
(5)如果 View 存在滑动冲突,应当处理好滑动冲突,否则会影响用户体验效果;有关滑动冲突的内容可以看Android中View的滑动冲突这篇文章。
3、自定义 View 的实例
我们这里就写一个直接继续于 View 的案例,我们就画一个椭圆,步骤如下所示;
(1)写一个 EllipseView并继承于 View;
package com.xe.myapplication4;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowManager;
/**
- Created by 86188 on 2022/7/7.
*/