ListView的常见使用技巧和扩展

1.使用ViewHolder模式提高效率

        通过在自定义Adapter中定义一个内部类ViewHolder,可提高50%的效率。关于自定义Adapter的简单封装,可以看我的这个博客

        http://blog.csdn.net/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
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值