Android自定义控件学习笔记二
本片笔记主要涉及的是继承View方式的自定义控件,并用这种方式来仿写绘制微信通讯录侧栏快速定位View。

本周刚好有反法西斯70周年庆典阅兵式,在这里我们也来领略一下程序员方阵的风采:
现在向我们走来的是程序员方阵!
他们穿着拖鞋,披着毛巾,
甩着十几天不洗的油头,
左手拿着键盘,右手举着鼠标,
腋下夹着USB转换器。
他们因睡眠不足而显得精神不振,
喊着微弱的口号走过主席台,主席问候:程序员们辛苦了!
程序员方队异口同声地答道:Hello World!
阿拉也是个程序员,自我调侃一下,闲话少说,接着干正事,如果我们继承View自定义一个控件,必须得做两件事,其一继承View构造方法,其二重写onDraw方法。
核心方法概要
重写View构造方法在上一篇笔记中以及介绍过了,也可以添加除了系统属性之外的其它自定义属性等等,可以参考Android自定义控件学习笔记一。这里重点讲一下onDraw方法。
onDraw()的方法是当在屏幕中需要显示界面的时候才调用的,android会判断某个界面是否需要绘制,如果不需要就根本不会调用到他的onDraw 方法,例如把自定义view设置为GONE,这时候根本看不到打出来的log了。onDraw方法中尽量不要新建对象否则会抛出下面提示:
Avoid object allocations during draw/layout operations (preallocate and reuse instead)
在ondraw/onlayout中尽量不要用new 对象的操作,因为ondraw/onlayout会经常被调用,这样比较耗内存。
onDraw常用的就是Paint和Canvas的两个对象实例:
Paint
画笔对象,相当于现实世界中的画笔,主要设置画笔的属性。
- setAntiAlias:设置画笔的锯齿效果;
- setColor:设置画笔颜色;
- setTextSize:设置字体尺寸;
- setStyle:设置画笔风格,空心或实心。
Canvas
画布,相当于现实世界中的画纸或画布,主要提供了绘制常见图形的方法。
- drawText(String text, float x, float y, Paint paint):绘制文本
- drawLine(float startX, float startY, float stopX, float stopY, Paint paint):绘制直线
- drawRect(float left, float top, float right, float bottom, Paint paint):绘制矩形
- drawCircle(float cx, float cy, float radius, Paint paint):绘制圆形
本文中会用到drawText方法,因此这里也多说一些该方法,方法中x、y参数取决与画笔Paint的Align位置,默认情况下是水平居左对起,y坐标基线对齐。更为详细的讲解可以参考这两篇文章关于Android Canvas.drawText方法中的坐标参数的正确解释和Android Canvas drawText实现中文垂直居中
Invalidate
invalidate()函数的主要作用是请求View树进行重绘,该函数可以由应用程序调用,或者由系统函数间接调用,例如setEnable(), setSelected(), setVisiblity()都会间接调用到invalidate()来请求View树重绘,更新View树的显示。更为详细的讲解可以参考Android中invalidate() 函数详解(结合Android 4.0.4 最新源码) 。
示例核心源码
onDraw
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (cellWidth == 0) {
cellWidth = getMeasuredWidth();
}
if (cellHeight == 0) {
cellHeight = getMeasuredHeight() / array.length;
}
// 将字符数组array等分绘制
for (int i = 0; i < array.length; i++) {
paint.getTextBounds(array[i] + "", 0, 1, bounds);
// 水平居中对齐 (cellWidth-字体所占宽度)/2 作为x起点
float x = (cellWidth - bounds.width()) / 2;
// y基线对齐
float y = (cellHeight + bounds.height()) / 2 + i * cellHeight;
paint.setColor(i == touchIndex ? Color.WHITE : Color.parseColor("#777777"));
canvas.drawText(array[i] + "", x, y, paint);
}
}
|
onTouchEvent
|
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
|
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
// 当手势滑动是改变自定义View背景色
setBackgroundColor(getResources().getColor(R.color.indexFocusbg));
//手势滑动时核心计算量touchIndex: 移动的y坐标位置与cellHeight比值恰巧是当前字符索引的下标
if (isSameIndex(y / cellHeight)) {
break;
}
touchIndex = y / cellHeight;
if (touchIndex >= 0 && touchIndex < array.length) {
String word = array[touchIndex] + "";
if (onTouchIndexListener != null) {
onTouchIndexListener.onTouchIndex(word);
}
// 滑动时重画以改变当前触摸字符色彩值
invalidate();
}
break;
case MotionEvent.ACTION_UP:
touchIndex = -1;
// 当手势移开时还原为默认色彩
setBackgroundColor(getResources().getColor(R.color.indexDefaultbg));
break;
}
return true;
}
|
Adapter适配器核心源码
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
String currentIndex = friend.pinyin.charAt(0) + "";
if (position > 0) {
//如果next的首字符与当前首字符相同则隐藏next的索引名称
String lastIndex = list.get(position - 1).pinyin.charAt(0) + "";
if (currentIndex.equals(lastIndex)) {
holder.tv_index.setVisibility(View.GONE);
} else {
holder.tv_index.setVisibility(View.VISIBLE);
holder.tv_index.setText(currentIndex);
}
} else {
holder.tv_index.setVisibility(View.VISIBLE);
holder.tv_index.setText(currentIndex);
}
|
汉子转化为拼音核心方法
|
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
|
public static String getPinYin(String hanzi) {
String pinyin = "";
if (TextUtils.isEmpty(hanzi))
return pinyin;
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
//转换为拼音大写字母
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
//统一转换为无声调的汉语拼音
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
char[] arr = hanzi.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (Character.isWhitespace(arr[i]))
continue;
//ASCII编码如果大于127则认为是汉字
if (arr[i] > 127) {
try {
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(arr[i], format);
if (pinyinArray == null) {
// 全角字符
pinyin += arr[i];
} else {
pinyin += pinyinArray[0];
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
pinyin += arr[i];
}
} else {
pinyin += arr[i];
}
}
return pinyin;
}
|
本篇文章地址:www.sunnyang.com/275.html

浙公网安备 33010602011771号