1.使用ViewHolder模式提高效率
通过在自定义Adapter中定义一个内部类ViewHolder,可提高50%的效率。关于自定义Adapter的简单封装,可以看我的这个博客
http://blog.youkuaiyun.com/afei__/article/details/51502134
2.设置项目分隔线
android:divider="@android:color/darker_gray"
android:dividerHeight="10dp"
如果我们不需要分割线,即可以使用以下代码
android:divider="@null"
3.隐藏ListView的滚动条
android:scrollbars="none"
4.取消ListView的点击效果
android:listSelector="@android:color/transparent"
5.设置ListView需要显示在第几项
listView.setSelection(N);
其中N就是需要显示的第N个Item。当然这个方法是瞬间完成的,我们还可以使用以下代码来实现平滑移动:
listView.smoothScrollBy(distance, duration);
listView.smoothScrollByOffset(offset);
listView.smoothScrollToPosition(position);
6.动态修改ListView的数据
修改ListView的数据时如果每次都重新创建对象显然效率不高,我们可以通过Adapter的notyfyDataChange()方法通知ListView数据更新。
7.处理空的ListView
当ListView列表中没有数据的时候,我们可以通过setEmptyView()给ListView设置一个在空数据下显示的默认提示页面。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ic_launcher" />
</FrameLayout>
在代码中,通过以下方式设置ListView空数据时显示的布局
ListView listView = (ListView) findViewById(R.id.listview);
listView.setEmptyView(findViewById(R.id.empty_view));
8.ListView滑动监听
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
// 滑动停止时
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
// 正在滑动
break;
case OnScrollListener.SCROLL_STATE_FLING:
// 手指抛动时,ListView的惯性滑行
break;
}
}
/**
* @param view ListView对象
* @param firstVisibleItem 当前我们能看到的第一个Item的ID(从0开始)
* @param visibleItemCount 当前能看到的Item总数
* @param totalItemCount 整个ListView的Item总数
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// 滚动时一直调用
}
});
所以,我们可以通过以下代码判断是否滚动到了最后一行
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
// 滚动到最后一行
}
可以通过以下代码判断滚动方向。通过定义一个成员变量lastVisibleItem来记录上次第一个可视Item的ID。
if (firstVisibleItem > lastVisibleItem) {
// 上滑
} else if (firstVisibleItem < lastVisibleItem){
// 下滑
}
lastVisibleItem = firstVisibleItem;
9.具有弹性的ListView
网上已经有很多重写的ListView来实现了弹性的效果,这里也介绍一种非常简单的方法来实现这种效果。
在我们查看ListView的源代码时,可以看到又一个控制滑动到边缘的处理方法,如下所示:
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY, int maxOverScrollX,
int maxOverScrollY, boolean isTouchEvent) {
}
我们可以看到这样一个参数:maxOverScrollY,它的默认值为0,只需修改这个值(使用你想设置的值),就可以让ListView具有弹性了。我们我们只需重写这个方法
@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,
256, isTouchEvent);
}
10.聊天ListView
通常我们的ListView的每一项都是相同的布局,但是我们所熟知的QQ、微信等聊天APP经常会有不同的布局,这种效果也是通过ListView实现的。
在定义BaseAdapter的时候,需要重写getView()方法,这个方法就是用来获取布局的,那么只需在获取布局的时候判断一下使用哪种布局就可以了,而且ListView在设计的时候已经考虑到这种情况了,所以它提供了两个方法:
@Override
public int getItemViewType(int position) {
return type;
}
@Override
public int getViewTypeCount() {
return number;
}
getItemViewType()方法用来返回第position个Item是何种类型,而getViewTypeCount()用来返回不同布局的个数。通过这两个方法再结合getView()就可以轻松完成聊天布局了。
首先实现两个布局——chat_item_itemin和chat_item_itemout,这里TextView的背景用到了9patch图片。
<?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:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<ImageView
android:id="@+id/icon_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/text_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/chatitem_in_bg"
android:gravity="center"
android:textSize="20sp" />
</LinearLayout>
<?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:gravity="center_vertical|right"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="@+id/text_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/chatitem_out_bg"
android:gravity="center"
android:textSize="20sp" />
<ImageView
android:id="@+id/icon_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
</LinearLayout>
同时,为了封装下聊天内容,便于在Adapter中获取数据信息,封装了一个Bean来保存数据
import android.graphics.Bitmap;
public class ChatItemListViewBean {
private int type;
private String text;
private Bitmap icon;
public ChatItemListViewBean() {
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Bitmap getIcon() {
return icon;
}
public void setIcon(Bitmap icon) {
this.icon = icon;
}
}
接下来就是完成最重要的BaseAdapter了,在getView()中判断使用的布局类型
package com.imooc.myapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class ChatItemListViewAdapter extends BaseAdapter {
private List<ChatItemListViewBean> mData;
private LayoutInflater mInflater;
public ChatItemListViewAdapter(Context context,
List<ChatItemListViewBean> 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 int getItemViewType(int position) {
ChatItemListViewBean bean = mData.get(position);
return bean.getType();
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
if (getItemViewType(position) == 0) {
holder = new ViewHolder();
convertView = mInflater.inflate(
R.layout.chat_item_itemin, null);
holder.icon = (ImageView) convertView.findViewById(
R.id.icon_in);
holder.text = (TextView) convertView.findViewById(
R.id.text_in);
} else {
holder = new ViewHolder();
convertView = mInflater.inflate(
R.layout.chat_item_itemout, null);
holder.icon = (ImageView) convertView.findViewById(
R.id.icon_out);
holder.text = (TextView) convertView.findViewById(
R.id.text_out);
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.icon.setImageBitmap(mData.get(position).getIcon());
holder.text.setText(mData.get(position).getText());
return convertView;
}
public final class ViewHolder {
public ImageView icon;
public TextView text;
}
}
最后,在测试的Activity中添加一些测试代码测试一下这个布局
import android.app.Activity;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class ChatItemListViewTest extends Activity {
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_item_main);
mListView = (ListView) findViewById(R.id.listView_chat);
ChatItemListViewBean bean1 = new ChatItemListViewBean();
bean1.setType(0);
bean1.setIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.in_icon));
bean1.setText("Hello how are you?");
ChatItemListViewBean bean2 = new ChatItemListViewBean();
bean2.setType(1);
bean2.setIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher));
bean2.setText("Fine thank you, and you?");
ChatItemListViewBean bean3 = new ChatItemListViewBean();
bean3.setType(0);
bean3.setIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.in_icon));
bean3.setText("I am fine too");
ChatItemListViewBean bean4 = new ChatItemListViewBean();
bean4.setType(1);
bean4.setIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher));
bean4.setText("Bye bye");
ChatItemListViewBean bean5 = new ChatItemListViewBean();
bean5.setType(0);
bean5.setIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.in_icon));
bean5.setText("See you");
List<ChatItemListViewBean> data = new ArrayList<ChatItemListViewBean>();
data.add(bean1);
data.add(bean2);
data.add(bean3);
data.add(bean4);
data.add(bean5);
mListView.setAdapter(new ChatItemListViewAdapter(this, data));
}
}
如果你想要看完整的代码,可以到以下链接查看或者拷贝到自己项目,参考自《Android群英传》第四章
https://github.com/xuyisheng/AndroidHeroes/tree/master/4.ListView/MyListView