自定义view(一)

  • content
    {:toc}

    0x01 介绍

1.进行view的绘制,学会一些自定义的操作

自定义View的步骤:

  1. 一般都需要重写onDraw onMeasure 这两个方法
  2. 其实View中带有onLayout这个方法,并不是只有ViewGroup中才有onLayout这个方法

自定义ViewGroup的步骤:

  1. 一般重写onMeasure, onLayout

0x02 自定义个简单的FlowLayout

1:什么是FlowLayout

FlowLayout:我这边弄的flowLayout就是当着横向摆放子控件的时候,如果这一行放不下后,然后就放另一行

1.1:测量 (onMeasure)
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
 /**
* 测量就是确定自己自定义控件的大小
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//漏了这一句,界面一直不显示,child的测量全是0
//实际就是测量一下子View

measureChildren(widthMeasureSpec, heightMeasureSpec);

int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);

//宽度默认是自己的宽度,实际上可以在AT_MOST模式下,进行一些计算
//如把所有的子控件的宽和padding+margin这些都加起来,这样换算成自己的宽度
int width = widthSize;
int height;


if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
//根据策略来进行子空间的摆放
int row = 1;
// int widthSpace = width; //宽度剩余空间
int tempWidth = 0;

for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
int childW = view.getMeasuredWidth();
if (childW + tempWidth <= width) {
tempWidth += width;
} else {
row++;
//换行了
tempWidth = 0;
}

// if (widthSpace >= childW) {
// widthSpace -= childW;
// } else {
// row++;
// widthSpace = width - childW;
// }

}

int childH = getChildAt(0).getMeasuredHeight();
height = childH * row;
}

setMeasuredDimension(width, height);
}
1.2:布局(onLayout)

策略的进行子View控件的摆放

策略:经过测量,当子View不能放在当前行的时候,就进行下一行的绘制

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
/**
* @param changed
* @param l
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

int offsetWidth = 0; //测量偏移的宽度
int offsetHeight = 0; //测量偏移的高度

int right = 0;

for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
int measuredWidth = childView.getMeasuredWidth();
int measuredHeight = childView.getMeasuredHeight();
//这一行还可以放下
if (offsetWidth + measuredWidth <= r) {
childView.layout(offsetWidth, offsetHeight, measuredWidth + offsetWidth, measuredHeight + offsetHeight);

//加上已经填充好的宽度
offsetWidth += measuredWidth;
} else { //换一行
offsetHeight += measuredHeight;
offsetWidth = 0; //我换一行了,所以重新开始计算偏移的宽度

childView.layout(offsetWidth, offsetHeight, measuredWidth + offsetWidth, measuredHeight + offsetHeight);

//这里也要加偏移量
offsetWidth += measuredWidth;
}
}

Log.e(TAG, "onLayout: changed: " + changed + ", l: " + l + ", t: " + t
+ ", r: " + r + ", b: " + b);
}