深入ListView

深入ListView

我们接着上一篇博客,对ListView进行更加深入的了解。

属性

android:cacheColorHint=”@color/white” 设置ListView滚动时的背景色
android:divider=”@color/red” 设置ListView分割线的颜色
android:dividerHeight=”1dp” 设置ListView分割线的高度

设置点击列表的背景

更改listview点击背景与更改Button点击背景和RadioButton选择图标的方法类似。
①在drawable文件夹下新建xml文档list_background.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@color/red" android:state_pressed="true"/> 
    <item android:drawable="@color/white"/>
</selector>

②在自定义的布局中加入属性background

android:background="@drawable/list_background"

提升ListView的运行效率

  1. 在上一篇博客中,StudentAdapter的getView()方法,每次都将布局重新加载了一遍,当ListView快速滚动的时候这就会成为性能的瓶颈。我们注意到getView()方法中还有一个参数convertView,这个参数用于将之前加载好的布局进行缓存,以便之后可以进行重用。
    我们在getView()方法中进行了判断,如果convertView为空,则使用inflater去加载布局,如果不为空则直接对convertView进行重用
  2. 我们每次在getView()方法中还是会调用View的findViewById()方法来获取一次控件的实例。此时可以借助一个ViewHolder来对这部分性能进行优化。
    新增一个内部类ViewHolder,用于对控件的实例进行缓存。当convertView为空,创建一个ViewHolder对象,并将控件的实例都存放在ViewHolder里,然后调用View的setTag()方法,将ViewHolder对象存储在View中。当convertView不为空时则调用View的getTag()方法,将ViewHolder重新取出
    优化后的代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Stuent student = arraylist.get(position);
    View view;
    ViewHolder viewHolder;
    if (convertView == null) {
        view = inflater.inflate(R.layout.simpleadapter_layout, null);
        viewHolder=new ViewHolder();
        viewHolder.image = (ImageView) view.findViewById(R.id.imageview);
        viewHolder.textview_name = (TextView) view.findViewById(R.id.textview_name);
        viewHolder.textview_age = (TextView) view.findViewById(R.id.textview_age);
        viewHolder.textview_sex = (TextView) view.findViewById(R.id.textview_sex);
        viewHolder.textview_hobby = (TextView) view.findViewById(R.id.textview_hobby);
        view.setTag(viewHolder);//将viewHolder存储在view中
        }else{
            view=convertView;
            viewHolder=(ViewHolder) view.getTag();//重新获取viewHolder
        }   
    viewHolder.textview_name.setText(student.getName());
    viewHolder.textview_age.setText(student.getAge());
    viewHolder.textview_sex.setText(student.getSex());
    viewHolder.textview_hobby.setText(student.getHobby());
    viewHolder.image.setImageResource(student.getImage());
    return view;
}
class ViewHolder{
    ImageView image;
    TextView textview_name;
    TextView textview_age;
    TextView textview_sex;
    TextView textview_hobby;
}

ListView其他常见的用法

在ListView加入其他点击控件

当我们在ListView中加入了其他的点击控件,如CheckBox,Button,RadioButton等,就会抢夺ListView的焦点,这时我们点击ListView就没有反应。
我们有两种办法可以解决这个问题:
①在ListView中设置屏蔽子控件抢夺ListView的焦点

android:descendantFocusability="blocksDescendants"  

②在子控件本身设置焦点属性为false。

android:focusable="false"

添加HeaderView和FooterView

  1. 首先我们要新建HeaderView或FooterView的布局xml文件
  2. 然后用LayoutInflater加载布局,生成View对象
  3. 最后调用addHeaderView()或addFooterView(),传入View对象即可。
    注意:当我们在ListView中添加了HeaderView之后,使用ListView点击事件时,ListView中item的索引要减1。

综合的代码示例

定义一个实体类 Fruit

public class Fruit {

    private int image;
    private String name;
    private boolean isChecked;

    public Fruit(int image, String name) {
        this.image = image;
        this.name = name;
    }

    public int getImage() {
        return image;
    }

    public void setImage(int image) {
        this.image = image;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isChecked() {
        return isChecked;
    }

    public void setChecked(boolean isChecked) {
        this.isChecked = isChecked;
    }   
}

为listview的子项指定自定义的布局

?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="horizontal" >
    <CheckBox android:id="@+id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="false" android:text="选择水果"/>
    <ImageView android:id="@+id/fruit" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
    <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content"/>  
</LinearLayout>

自定义适配器FruitAdapter.java

mport java.util.ArrayList;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.TextView;

public class FruitAdapter extends BaseAdapter {
    private LayoutInflater inflater;
    private ArrayList<Fruit> list;

    public FruitAdapter(LayoutInflater inflater, ArrayList<Fruit> list) {
        this.inflater = inflater;
        this.list = list;
    }

    /** * 全选 */
    public void checkAll() {
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setChecked(true);
        }
        notifyDataSetChanged();
    }

    /** * 反选 */
    public void reverse() {
        for (int i = 0; i < list.size(); i++) {
            selectItem(i);
        }
    }

    /** * 点击ListView可以勾选住CheckBox * * @param position 当前ListView的位置 */
    public void selectItem(int position) {
        boolean isChecked = list.get(position).isChecked();
        isChecked = !isChecked;
        list.get(position).setChecked(isChecked);
        notifyDataSetChanged();// 刷新界面
    }

    @Override
    public int getCount() {

        return list.size();
    }

    @Override
    public Object getItem(int arg0) {

        return arg0;
    }

    @Override
    public long getItemId(int arg0) {

        return arg0;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup arg2) {

        Fruit fruit = list.get(position);
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = inflater.inflate(R.layout.fruit_layout, null);
            viewHolder = new ViewHolder();
            viewHolder.checkbox = (CheckBox) view.findViewById(R.id.checkbox);
            viewHolder.image = (ImageView) view.findViewById(R.id.fruit);
            viewHolder.name = (TextView) view.findViewById(R.id.textview);
            view.setTag(viewHolder);
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.image.setImageResource(fruit.getImage());
        viewHolder.name.setText(fruit.getName());
        viewHolder.checkbox
                .setOnCheckedChangeListener(new OnCheckedChangeListener() {

                    @Override
                    public void onCheckedChanged(CompoundButton buttonView,
                            boolean isChecked) {
                        list.get(position).setChecked(isChecked);//如果勾选,将该项设为true
                    }
                });
        viewHolder.checkbox.setChecked(fruit.isChecked());//将ViewHolder中的实例重新设置为false
        return view;
    }

    class ViewHolder {
        CheckBox checkbox;
        ImageView image;
        TextView name;
    }
}

HeaderView和FooterView的布局文件

<?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" >
    <Button android:id="@+id/button_quan" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="全选"/>
</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:orientation="vertical" >
    <Button android:id="@+id/button_fan" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="反选"/>
</LinearLayout>

MainActivity

import java.util.ArrayList;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.app.Activity;

public class MainActivity extends Activity {
    private LayoutInflater inflater;
    private FruitAdapter adapter;
    private ArrayList<Fruit> list;
    private View fruitHeaderView;
    private View fruitFooterView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        list = new ArrayList<Fruit>();
        for (int i = 0; i < 5; i++) {
            Fruit apple = new Fruit(R.drawable.apple, "苹果");
            Fruit banana = new Fruit(R.drawable.banana, "香蕉");
            Fruit grape = new Fruit(R.drawable.grape, "葡萄");
            Fruit strawberry = new Fruit(R.drawable.strawberry, "草莓");
            list.add(apple);
            list.add(banana);
            list.add(grape);
            list.add(strawberry);
        }
        inflater = getLayoutInflater();
        adapter = new FruitAdapter(inflater, list);
        ListView listView = (ListView) findViewById(R.id.listview_fruit);
        fruitHeaderView = inflater.inflate(R.layout.fruit_header, null);
        listView.addHeaderView(fruitHeaderView);
        Button button_quan = (Button) fruitHeaderView
                .findViewById(R.id.button_quan);
        button_quan.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                adapter.checkAll();// 全选
            }
        });
        fruitFooterView = inflater.inflate(R.layout.fruit_footer, null);
        listView.addFooterView(fruitFooterView);
        Button button_fan = (Button) fruitFooterView
                .findViewById(R.id.button_fan);
        button_fan.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                adapter.reverse();// 反选
            }
        });
        listView.setAdapter(adapter);
        //点击listview,勾选中当前checkbox
        listView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View view,
                    int position, long id) {
                // 因为加了HeaderView,所以索引要减1
                adapter.selectItem(position - 1);// 调用点击lsitview选择checkbox的方法
                Toast.makeText(MainActivity.this,
                        "选择的水果为:" + list.get(position - 1).getName(),
                        Toast.LENGTH_SHORT).show();
            }
        });
    }
}

运行结果:

点击ListView,会勾选CheckBox
深入ListView_第1张图片
点击全选,则全部选中
深入ListView_第2张图片
点击反选,则去掉之前选中的其余部分

你可能感兴趣的:(ListView,viewholder)