在ListView中实现顶部和底部内容指示器

本文介绍如何为Android的ListView自定义顶部和底部的箭头指示器,并提供了一个具体的实现示例,包括代码和XML布局文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.open-open.com/lib/view/open1324995841233.html

顶部指示器?
这是什么?
好吧,我承认这是我自己想出来的词,因为我不知道它有什么学名,究竟是什么呢?看下这个图就知道了。
顶部指示器示例
这是我们的美工MM画的,偶的神呐,这虽然很漂亮,不过也让人头疼,这个箭头应该在滚到顶部的时候消失,滚下来的时候(即有条目隐藏的时候)才显示,类似的底部指示器也要有这样的效果。事实上默认的ListView和ScrollView都已经有了类似的效果,在顶部或底部还有更多内容时,会有部分渐变虚化的效果,不过美工已经设计了这样的效果,那么我们就来做吧。
出于省事的目的,本教程中的例子会基于上一篇教程来修改,主要是添加1个继承自ListView的类,以及修改布局定义文件。

ArrowListView控件的编写

001 package net.learningandroid.lib.view;
002   
003 import net.learningandroid.lib.R;
004 import android.content.Context;
005 import android.graphics.Bitmap;
006 import android.graphics.Canvas;
007 import android.graphics.Paint;
008 import android.graphics.Rect;
009 import android.graphics.drawable.BitmapDrawable;
010 import android.util.AttributeSet;
011 import android.util.Log;
012 import android.view.View;
013 import android.widget.ListView;
014   
015 /**
016  * 支持上下箭头的ListView
017  *
018  * <a class="referer" href="http://my.oschina.net/arthor" target="_blank">@author</a> Mr. Lu
019  */
020 public class ArrowListView extends ListView {
021   
022     private final float scale = getContext().getResources().getDisplayMetrics().density;
023     private float topArrowPadding;
024     private float bottomArrowPadding;
025   
026     private static float DEFAULT_TOP_PADDING_DP = 2.0f;
027     private static float DEFAULT_BOTTOM_PADDING_DP = 2.0f;
028   
029     public ArrowListView(Context context, AttributeSet attrs) {
030         super(context, attrs);
031   
032         String strTopArrowPadding = attrs.getAttributeValue(null,
033                 "topArrowPadding");
034         String strBottomArrowPadding = attrs.getAttributeValue(null,
035                 "bottomArrowPadding");
036   
037         topArrowPadding = convertDisplayUom(strTopArrowPadding,
038                 DEFAULT_TOP_PADDING_DP);
039         bottomArrowPadding = convertDisplayUom(strBottomArrowPadding,
040                 DEFAULT_BOTTOM_PADDING_DP);
041   
042         Log.v("ArrowListView", String.valueOf(topArrowPadding));
043     }
044   
045     /**
046      * 单位转换
047      */
048     private float convertDisplayUom(String sour, float defaultValue) {
049         try {
050             if (sour.toLowerCase().endsWith("px")) {
051                 return Float.parseFloat(sour.toLowerCase().replace("px"""));
052             else if (sour.toLowerCase().endsWith("dp")) {
053                 return Integer.parseInt(sour.toLowerCase().replace("dp",
054                         ""))
055                         * scale + 0.5f;
056             }
057         catch (Exception e) {
058         }
059   
060         return (defaultValue * scale + 0.5f);
061     }
062   
063     /**
064      * onDraw方法,根据ListView滚动位置绘出箭头.
065      */
066     @Override
067     protected void onDraw(Canvas canvas) {
068         super.onDraw(canvas);
069         Paint paint = new Paint();
070   
071         // 取得箭头的图片,此处是固定图片,其实上可以做成配置方式
072         Bitmap topPic = ((BitmapDrawable) getResources().getDrawable(
073                 R.drawable.arrow_up)).getBitmap();
074         Bitmap bottomPic = ((BitmapDrawable) getResources().getDrawable(
075                 R.drawable.arrow_down)).getBitmap();
076   
077         // 取得ListView的绘制区域大小
078         Rect r = new Rect();
079         this.getDrawingRect(r);
080   
081         // 计算箭头的绘制位置
082         float top = r.top + topArrowPadding;
083         float bottom = r.bottom - bottomArrowPadding - bottomPic.getHeight();
084         float left = r.left + (r.right - r.left - topPic.getWidth()) / 2;
085   
086         // 计算是否需要绘制
087         boolean drawTop = false;
088         boolean drawBottom = false;
089   
090         if (this.getChildCount() > 0) {
091             Rect rTop = new Rect();
092             this.getChildAt(0).getLocalVisibleRect(rTop);
093             Rect rBottom = new Rect();
094             View lastChild = this.getChildAt(this.getChildCount() - 1);
095             lastChild.getLocalVisibleRect(rBottom);
096   
097             drawTop = (this.getFirstVisiblePosition() > 0 || this
098                             .getFirstVisiblePosition() == 0
099                             && rTop.top > 0);
100             drawBottom = (this.getLastVisiblePosition() < this.getAdapter()
101                             .getCount() - 1 || this.getLastVisiblePosition() == this
102                             .getAdapter().getCount() - 1
103                             && rBottom.bottom < lastChild.getHeight());
104         }
105         // 绘出箭头
106         if (drawTop) {
107             canvas.drawBitmap(topPic, left, top, paint);
108         }
109   
110         if (drawBottom) {
111             canvas.drawBitmap(bottomPic, left, bottom, paint);
112         }
113     }
114 }

就要点解释一下上面这段代码:
注意构造方法,我们必须继承public ArrowListView(Context context, AttributeSet attrs),这样才可以让这个类在xml定义文件中使用。
还要注意到,这里用了attrs.getAttributeValue来读取XML定义文件中的属性,其实有更好的方法,容我下次再讲解,这里先偷个懒。
convertDisplayUom方法是用来将dp转换成px的,可以看到由于我们用了getAttributeValue的方式,所以需要手动将String转成Float,很麻烦。
最后就是onDraw啦,计算出画箭头的位置,画出来就行了。
接下来就是布局文件的编写了

ArrowListView在XML文件中的使用

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout
03     xmlns:android="http://schemas.android.com/apk/res/android"
04     android:layout_width="fill_parent" android:layout_height="fill_parent"
05  
06     android:orientation="vertical"
07     >
08     <TextView
09         android:text="Arrow List View Sample"
10         android:layout_width="fill_parent" android:layout_height="wrap_content"
11  
12     />
13     <net.learningandroid.lib.view.ArrowListView
14         android:id="@+id/arrowListView"
15         android:layout_width="fill_parent" android:layout_height="wrap_content"
16         android:paddingTop="15dp" android:paddingBottom="20dp"
17  
18         android:layout_margin="10dp"
19         android:background="@drawable/float_panel"
20         android:layout_weight="1"
21         android:cacheColorHint="#FFEDEDED" android:divider="#00EDEDED"
22  
23         topArrowPadding="5dp" bottomArrowPadding="10dp"
24     />
25 </LinearLayout>

这里需要注意的是自定义控件和其中的属性的写法,不再是ListView了,而是你自己编写的控件类的类名。其它的内容就是定义padding,background,以及取消了分隔线的显示。
用这个布局文件替代上一篇教程中的布局文件,但Adapter的定义不变,因为ArrowListView是继承自ListView的,所以原先的Adapter的使用是一样的。

最后我们来看下效果:
带内容指示器的ListView最终效果图
如何?只需要小心的调整ListView的Padding和ArrowPadding的值就可以控制箭头出现的位置,如果需要控制更多,比如更换图片,或者当顶部无内容时让箭头变暗、有内容时变亮,都可以用同样的方法。
并且,如果修改了Attribute的读取方法之后,还可以通过xml文件来指定箭头的图片。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值