虽然在 Android 5.X 时代,RecyclerView 在很多地方都在逐步取代 ListView ,但使用范围依然非常的广泛,下面展示使用 ListView 的常用技巧和拓展以及示例代码。
1.使用 ViewHolder 利用视图缓存机制,避免每次 findViewById() 实例化控件####
public class NotifyAdapter extends BaseAdapter {
private List<String> mData;
private LayoutInflater mInflater;
public NotifyAdapter(Context context, List<String> data) {
this.mData = data;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
// 判断是否缓存
if (convertView == null) {
holder = new ViewHolder();
// 通过LayoutInflater实例化布局
convertView = mInflater.inflate(R.layout.notify_item, null);
holder.img = (ImageView) convertView.findViewById(R.id.imageView);
holder.title = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(holder);
} else {
// 通过tag找到缓存的布局
holder = (ViewHolder) convertView.getTag();
}
// 设置布局中控件要显示的视图
holder.img.setBackgroundResource(R.drawable.ic_launcher);
holder.title.setText(mData.get(position));
return convertView;
}
public final class ViewHolder {
public ImageView img;
public TextView title;
}
}
2.关于 ListView 常用设置
- 设置 Item 间的分隔线
android:divider="@android:color/black"
android:dividerHeight="5dp"
- 设置分隔线为透明
android:divider="@null"
- 隐藏滚动条
android:scrollbars="none"
- 取消 Item 的点击效果
android:listSelector="#00000000"
- 设置 ListView 显示第几项
mListView.setSelection(2);
- 遍历 ListView 中所有的 Item
for (int i = 0;i < mListView.getChildCount();i++) {
View view = mListView.getChildAt(i);
}
- 当列表中无数据时,应当给予无数据的提示
mListView.setEmptyView(findViewById(R.id.button));
3.ListView 滑动监听
- 通过 OnTouchListener 可判断滑动方向,在不同事件做相应处理。
mListView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_UP:
Log.d(TAG, "onTouch: " + "手势离开");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "onTouch: " + "手势移动");
break;
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "onTouch: " + "手势触摸");
break;
}
return false;
}
});
- 通过 OnScrollListener 对 ListView 滑动监听,判断各种手势。
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case AbsListView.OnScrollListener
.SCROLL_STATE_IDLE:
Log.d(TAG, "onScrollStateChanged: 滑动停止时");
break;
case AbsListView.OnScrollListener
.SCROLL_STATE_TOUCH_SCROLL:
Log.d(TAG, "onScrollStateChanged: 正在滑动时");
break;
case AbsListView.OnScrollListener
.SCROLL_STATE_FLING:
Log.d(TAG, "onScrollStateChanged: 手指离开屏幕惯性滑动");
break;
}
}
int lastVisibleItemPosition = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
Log.d(TAG, "onScroll: onScroll"); //滑动时会一直调用
//当前能看见第一个 Item 的 ID,显示一小半的也算整个 Item
Log.d(TAG, "onScroll: " + firstVisibleItem);
//当前能看见的 Item 总数
Log.d(TAG, "onScroll: " + visibleItemCount);
//整个 ListView 的 Item 总数
Log.d(TAG, "onScroll: " + totalItemCount);
if (firstVisibleItem + visibleItemCount ==
totalItemCount && totalItemCount > 0) {
Log.d(TAG, "onScroll: 滑动到了最后一行");
}
if (firstVisibleItem > lastVisibleItemPosition) {
Log.d(TAG, "onScroll: 上滑");
} else if (firstVisibleItem < lastVisibleItemPosition) {
Log.d(TAG, "onScroll: 下滑");
}
lastVisibleItemPosition = firstVisibleItem;
}
});
- 获取当前可视的 Item 的位置
int lastVisiblePosition = mListView.getLastVisiblePosition
Log.d(TAG, "可视区域内最后一个 Item 的 id " + lastVisiblePosition);
int firstVisiblePosition = mListView.getFirstVisiblePositi
Log.d(TAG, "可视区域内第一个 Item 的 id" + firstVisiblePosition);
3.关于 ListView 常用拓展
- 具有弹性的 ListView ,当列表滑倒顶端或者底端,可以多滑动一段距离。
需要继承 ListView ,重写以下方法,mMaxOverDistance 是可继续滑动的距离
@Override
protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
return super.overScrollBy(deltaX, deltaY,
scrollX, scrollY,
scrollRangeX, scrollRangeY,
maxOverScrollX, mMaxOverDistance,
isTouchEvent);
}
保证不同分辨率的弹性滑动距离保持基本一致,通过屏幕的 density 计算。
private static int mMaxOverDistance = 50;
private void initView() {
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
float density = metrics.density;
mMaxOverDistance = (int) (density * mMaxOverDistance);
}