我们经常会看见新浪微博,人人的android客户端在显示大量数据的时候,右边会有一个快速拖动按钮,使用它我们可以快速的上下拖动,当我们停止拖动列表时,大约1秒左右,滑块又会消失。这是如何实现的呢?其实很简单,在android的标签中提供了这样一个属性:android:fastScrollEnabled.我们将这个属性设置为true就可以了,但是注意了,listView当中的数据要超过4个屏幕时才会出现这个小滑块,否则小滑块是不会出现的。
如下图所示:
接下来我们就来实现这样一个可以迅速滑动的ListView。
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/myListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fastScrollEnabled="true"
>
</ListView>
</RelativeLayout>
在ListView标签中记得要设置fastScrollEnabled的值为true。
List_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/itemName"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="30sp"
/>
<TextView
android:id="@+id/author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
/>
</LinearLayout>
主程序MainActivity.java:
package org.list.activity;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.list.adapter.MyListAdapter;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.AbsListView;
import android.widget.ListView;
import android.support.v4.app.NavUtils;
public class MainActivity extends Activity {
private ListView list;
private List<HashMap<String,String>> data;
private MyListAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
public void init()
{
list=(ListView)findViewById(R.id.myListView);
data=new ArrayList<HashMap<String,String>>();
adapter=new MyListAdapter(data,this);
for(int i=0;i<50;i++)
{
HashMap map=new HashMap();
map.put("itemName", "item"+i);
map.put("author", "viking");
data.add(map);
}
list.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
接下来是MyListAdapter.java:
package org.list.adapter;
import java.util.HashMap;
import java.util.List;
import java.util.zip.Inflater;
import org.list.activity.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MyListAdapter extends BaseAdapter
{
private List<HashMap<String,String>> data;
private LayoutInflater inflater;
public MyListAdapter(List<HashMap<String,String>> data,Context context)
{
super();
this.data = data;
inflater=LayoutInflater.from(context);
}
@Override
public int getCount()
{
if(data!=null)
{
return data.size();
}
return 0;
}
@Override
public Object getItem(int position)
{
if(data!=null)
{
return data.get(position);
}
return null;
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if(convertView==null)
{
convertView=inflater.inflate(R.layout.list_item, null);
holder=new ViewHolder();
holder.itemName=(TextView) convertView.findViewById(R.id.itemName);
holder.author=(TextView) convertView.findViewById(R.id.author);
convertView.setTag(holder);
}
else
{
holder=(ViewHolder)convertView.getTag();
}
HashMap<String,String> map=data.get(position);
holder.itemName.setText(map.get("itemName").toString());
holder.author.setText(map.get("author").toString());
return convertView;
}
class ViewHolder
{
TextView itemName;
TextView author;
}
}
到此为止,咱们已经实现了ListView当中的快速滑动的功能了,有人说了,为什么那个快速滑动小块这么难看啊?能不能换成其他图片啊?
为此我翻了一下帮助文档,发现ListView组件并没有提供修改快速滑动图像的API,因此不能直接修改快速滑块的图像。但可以通过反射技术修改快速滑块图像。
那我们怎么去使用反射呢?首先我们必须知道对谁进行反射。
我首先查看了ListView的源代码,发现里面变没有fastScrollEnabled这个属性,那么就只能去他的父类AbsListView中去看看。果然,在549行看到了以下代码:
如果mFastScroller这个对象为null,就实例化一个FastScroller。那我们接着进FastScroller类中看看构造方法。
构造方法当中执行了init(context)方法,我们跟过去。
在init方法中有一个useThumbDrawable的方法,它需要一个Drawable的参数。我们可以看见引用的com.android.internal.R.drawable.scrollbar_handle_accelerated_anim2名字是不是跟快速滑动滑块很类似啊?我们继续跟进这个方法。
发现传进去的参数赋值给了一个mThumbDrawable变量。接着在draw方法当中又发现了一下代码:
看来这个变量是要画在画布上的,所以我就猜测这个变量就是我们快速滑动滑块。接下来就好办了,我们用反射技术,把这个值改掉不就行了?
/首先要通过AbsListView.mFastScroller变量获取到FastScroller对象
Field field=AbsListView.class.getDeclaredField("mFastScroller");
//因为mFastScroller是私有的,所以我们必须设置它能够被访问
field.setAccessible(true);
Object object=field.get(list);
//获取FastScroller.mThumbDrawable变量的Field对象
field=field.getType().getDeclaredField("mThumbDrawable");
field.setAccessible(true);
//获取FastScroller.mThumbDrawable变量的值
Drawable draw=(Drawable)field.get(object);
//转载新的快速滑动图像
draw=getResources().getDrawable(R.drawable.ic_launcher);
//重新设置快速滑动图像
field.set(object,draw);
将以上代码放在onCreate方法中,就可以将快速滑动滑块的图像改掉了。
如下图所示: