顶部指示器?
这是什么?
好吧,我承认这是我自己想出来的词,因为我不知道它有什么学名,究竟是什么呢?看下这个图就知道了。
这是我们的美工mm画的,偶的神呐,这虽然很漂亮,不过也让人头疼,这个箭头应该在滚到顶部的时候消失,滚下来的时候(即有条目隐藏的时候)才显示,类似的底部指示器也要有这样的效果。事实上默认的listview和scrollview都已经有了类似的效果,在顶部或底部还有更多内容时,会有部分渐变虚化的效果,不过美工已经设计了这样的效果,那么我们就来做吧。
出于省事的目的,本教程中的例子会基于上一篇教程来修改,主要是添加1个继承自listview的类,以及修改布局定义文件。
arrowlistview控件的编写
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
package net.learningandroid.lib.view;
import net.learningandroid.lib.r;
import android.content.context;
import android.graphics.bitmap;
import android.graphics.canvas;
import android.graphics.paint;
import android.graphics.rect;
import android.graphics.drawable.bitmapdrawable;
import android.util.attributeset;
import android.util.log;
import android.view.view;
import android.widget.listview;
/**
* 支持上下箭头的listview
*
* <a class="referer" href="http://my.oschina.net/arthor" target="_blank">@author</a> mr. lu
*/
public class arrowlistview extends listview {
private final float scale = getcontext().getresources().getdisplaymetrics().density;
private float toparrowpadding;
private float bottomarrowpadding;
private static float default_top_padding_dp = 2 .0f;
private static float default_bottom_padding_dp = 2 .0f;
public arrowlistview(context context, attributeset attrs) {
super (context, attrs);
string strtoparrowpadding = attrs.getattributevalue( null ,
"toparrowpadding" );
string strbottomarrowpadding = attrs.getattributevalue( null ,
"bottomarrowpadding" );
toparrowpadding = convertdisplayuom(strtoparrowpadding,
default_top_padding_dp);
bottomarrowpadding = convertdisplayuom(strbottomarrowpadding,
default_bottom_padding_dp);
log.v( "arrowlistview" , string.valueof(toparrowpadding));
}
/**
* 单位转换
*/
private float convertdisplayuom(string sour, float defaultvalue) {
try {
if (sour.tolowercase().endswith( "px" )) {
return float .parsefloat(sour.tolowercase().replace( "px" , "" ));
} else if (sour.tolowercase().endswith( "dp" )) {
return integer.parseint(sour.tolowercase().replace( "dp" ,
"" ))
* scale + 0 .5f;
}
} catch (exception e) {
}
return (defaultvalue * scale + 0 .5f);
}
/**
* ondraw方法,根据listview滚动位置绘出箭头.
*/
@override
protected void ondraw(canvas canvas) {
super .ondraw(canvas);
paint paint = new paint();
// 取得箭头的图片,此处是固定图片,其实上可以做成配置方式
bitmap toppic = ((bitmapdrawable) getresources().getdrawable(
r.drawable.arrow_up)).getbitmap();
bitmap bottompic = ((bitmapdrawable) getresources().getdrawable(
r.drawable.arrow_down)).getbitmap();
// 取得listview的绘制区域大小
rect r = new rect();
this .getdrawingrect(r);
// 计算箭头的绘制位置
float top = r.top + toparrowpadding;
float bottom = r.bottom - bottomarrowpadding - bottompic.getheight();
float left = r.left + (r.right - r.left - toppic.getwidth()) / 2 ;
// 计算是否需要绘制
boolean drawtop = false ;
boolean drawbottom = false ;
if ( this .getchildcount() > 0 ) {
rect rtop = new rect();
this .getchildat( 0 ).getlocalvisiblerect(rtop);
rect rbottom = new rect();
view lastchild = this .getchildat( this .getchildcount() - 1 );
lastchild.getlocalvisiblerect(rbottom);
drawtop = ( this .getfirstvisibleposition() > 0 || this
.getfirstvisibleposition() == 0
&& rtop.top > 0 );
drawbottom = ( this .getlastvisibleposition() < this .getadapter()
.getcount() - 1 || this .getlastvisibleposition() == this
.getadapter().getcount() - 1
&& rbottom.bottom < lastchild.getheight());
}
// 绘出箭头
if (drawtop) {
canvas.drawbitmap(toppic, left, top, paint);
}
if (drawbottom) {
canvas.drawbitmap(bottompic, left, bottom, paint);
}
}
}
|
就要点解释一下上面这段代码:
注意构造方法,我们必须继承public arrowlistview(context context, attributeset attrs),这样才可以让这个类在xml定义文件中使用。
还要注意到,这里用了attrs.getattributevalue来读取xml定义文件中的属性,其实有更好的方法,容我下次再讲解,这里先偷个懒。
convertdisplayuom方法是用来将dp转换成px的,可以看到由于我们用了getattributevalue的方式,所以需要手动将string转成float,很麻烦。
最后就是ondraw啦,计算出画箭头的位置,画出来就行了。
接下来就是布局文件的编写了
arrowlistview在xml文件中的使用
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
|
<?xml version= "1.0" encoding= "utf-8" ?>
<linearlayout
xmlns:android= "http://schemas.android.com/apk/res/android"
android:layout_width= "fill_parent" android:layout_height= "fill_parent"
android:orientation= "vertical"
>
<textview
android:text= "arrow list view sample"
android:layout_width= "fill_parent" android:layout_height= "wrap_content"
/>
<net.learningandroid.lib.view.arrowlistview
android:id= "@+id/arrowlistview"
android:layout_width= "fill_parent" android:layout_height= "wrap_content"
android:paddingtop= "15dp" android:paddingbottom= "20dp"
android:layout_margin= "10dp"
android:background= "@drawable/float_panel"
android:layout_weight= "1"
android:cachecolorhint= "#ffededed" android:divider= "#00ededed"
toparrowpadding= "5dp" bottomarrowpadding= "10dp"
/>
</linearlayout>
|
这里需要注意的是自定义控件和其中的属性的写法,不再是listview了,而是你自己编写的控件类的类名。其它的内容就是定义padding,background,以及取消了分隔线的显示。
用这个布局文件替代上一篇教程中的布局文件,但adapter的定义不变,因为arrowlistview是继承自listview的,所以原先的adapter的使用是一样的。
最后我们来看下效果:
如何?只需要小心的调整listview的padding和arrowpadding的值就可以控制箭头出现的位置,如果需要控制更多,比如更换图片,或者当顶部无内容时让箭头变暗、有内容时变亮,都可以用同样的方法。
并且,如果修改了attribute的读取方法之后,还可以通过xml文件来指定箭头的图片。