自定义View

来源:互联网 发布:淘客优惠券网站源码 编辑:程序博客网 时间:2024/06/03 16:08

前言

自定义View是Android开发者必须了解的基础
今天,我将手把手教你写一个自定义View,并理清自定义View所有应该的注意点
阅读本文前,请先阅读我写的一系列自定义View文章
自定义View基础 - 最易懂的自定义View原理系列(1)
自定义View Measure过程 - 最易懂的自定义View原理系列(2)
自定义View Layout过程 - 最易懂的自定义View原理系列(3)
自定义View Draw过程- 最易懂的自定义View原理系列(4)
目录

目录

  1. 自定义View的分类

自定义View一共分为两大类,具体如下图:
分类

  1. 具体介绍 & 使用场景

对于自定义View的类型介绍及使用场景如下图:
具体介绍 & 使用场景

  1. 使用注意点

在使用自定义View时有很多注意点(坑),希望大家要非常留意:
使用注意点

3.1 支持特殊属性

支持wrap_content
如果不在onMeasure()中对wrap_content作特殊处理,那么wrap_content属性将失效

具体原因请看文章:为什么你的自定义View wrap_content不起作用?
支持padding & margin
如果不支持,那么padding和margin(ViewGroup情况)的属性将失效

对于继承View的控件,padding是在draw()中处理
对于继承ViewGroup的控件,padding和margin会直接影响measure和layout过程
3.2 多线程应直接使用post方式

View的内部本身提供了post系列的方法,完全可以替代Handler的作用,使用起来更加方便、直接。

3.3 避免内存泄露

主要针对View中含有线程或动画的情况:当View退出或不可见时,记得及时停止该View包含的线程和动画,否则会造成内存泄露问题。

启动或停止线程/ 动画的方式:
1. 启动线程/ 动画:使用view.onAttachedToWindow(),因为该方法调用的时机是当包含View的Activity启动的时刻
2. 停止线程/ 动画:使用view.onDetachedFromWindow(),因为该方法调用的时机是当包含View的Activity退出或当前View被remove的时刻
3.4 处理好滑动冲突

当View带有滑动嵌套情况时,必须要处理好滑动冲突,否则会严重影响View的显示效果。

  1. 具体实例

接下来,我将用自定义View中最常用的继承View来说明自定义View的具体应用和需要注意的点

4.1 继承VIew的介绍

Paste_Image.png

在下面的例子中,我将讲解:

如何实现一个基本的自定义View(继承VIew)
如何自身支持wrap_content & padding属性
如何为自定义View提供自定义属性(如颜色等等)

实例说明:画一个实心圆

4.2 具体步骤

创建自定义View类(继承View类)
布局文件添加自定义View组件
注意点设置(支持wrap_content & padding属性自定义属性等等)
下面我将逐个步骤进行说明:
步骤1:创建自定义View类(继承View类)

CircleView.java

// 用于绘制自定义View的具体内容
// 具体绘制是在复写的onDraw()内实现

public class CircleView extends View {

// 设置画笔变量Paint mPaint1;// 自定义View有四个构造函数// 如果View是在Java代码里面new的,则调用第一个构造函数public CircleView(Context context){    super(context);    // 在构造函数里初始化画笔的操作    init();}

// 如果View是在.xml里声明的,则调用第二个构造函数
// 自定义属性是从AttributeSet参数传进来的
public CircleView(Context context,AttributeSet attrs){
super(context, attrs);
init();

}

// 不会自动调用
// 一般是在第二个构造函数里主动调用
// 如View有style属性时
public CircleView(Context context,AttributeSet attrs,int defStyleAttr ){
super(context, attrs,defStyleAttr);
init();
}

//API21之后才使用// 不会自动调用// 一般是在第二个构造函数里主动调用// 如View有style属性时public  CircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {    super(context, attrs, defStyleAttr, defStyleRes);}// 画笔初始化private void init() {    // 创建画笔    mPaint1 = new Paint ();    // 设置画笔颜色为蓝色    mPaint1.setColor(Color.BLUE);    // 设置画笔宽度为10px    mPaint1.setStrokeWidth(5f);    //设置画笔模式为填充    mPaint1.setStyle(Paint.Style.FILL);}// 复写onDraw()进行绘制  @Overrideprotected void onDraw(Canvas canvas) {    super.onDraw(canvas);   // 获取控件的高度和宽度    int width = getWidth();    int height = getHeight();    // 设置圆的半径 = 宽,高最小值的2分之1    int r = Math.min(width, height)/2;    // 画出圆(蓝色)    // 圆心 = 控件的中央,半径 = 宽,高最小值的2分之1    canvas.drawCircle(width/2,height/2,r,mPaint1);}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
特别注意:
1. View的构造函数一共有4个,具体使用请看:深入理解View的构造函数和
理解View的构造函数
2. 对于绘制内容为何在复写onDraw()里实现,具体请看我写的文章:自定义View Draw过程- 最易懂的自定义View原理系列(4)

步骤2:在布局文件中添加自定义View类的组件

activity_main.xml

原创粉丝点击