第三章 ListView的用法

ListView实战教程
本文详细介绍ListView的基本用法,包括创建和填充数据,为ListView项添加图片,优化ListView性能,以及实现点击事件。

一.ListView的简单用法
1.创建一个布局activity_main.xml,加入ListView控件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/list_view"/>
</LinearLayout>

2.修改MainActivity中的代码

package com.example.kim.listview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {

    private String[] date = {"Apple","Banana","Orange","Watermelon",
            "Pear","Grape","Pineapple","Strawberry","Cherry","Mango",
            "Apple","Banana","Orange","Watermelon",
            "Pear","Grape","Pineapple","Strawberry","Cherry","Mango"};
    //定义一个String数组,用于存放数据
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                MainActivity.this,android.R.layout.simple_list_item_1,date);
        //数组中数据无法直接传给ListView 所以要借助适配器
        //定义一个泛型为String的ArrayAdapter,并传入context,ListView子项布局id,还有数组date
        ListView listView = (ListView)findViewById(R.id.list_view);
        listView.setAdapter(adapter);
        //调用ListView的setAdapter对象,将构建好的适配器对象传递进去Q
    }
}

效果图

二.为ListView中每行的物品添加图样
1.定义一个实体类Fruit,作为ListView的适配类型

package com.example.kim.listview;

/**
 * Created by KIM on 2017/4/26.
 */

public class Fruit {
    private String name;
    private int imageId;

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

    public String getName(){
        return name;
    }
    public int getImageId(){
        return imageId;
    }
}

2.为ListView子项指定自定义布局,新建fruit_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" 
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:id="@+id/fruit_image"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:id="@+id/fruit_name"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"/>
</LinearLayout> 

3.创建一个自定义适配器FruitAdapter

package com.example.kim.listview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by KIM on 2017/4/26.
 */

//定义自定义适配器 继承ArrayAdapter 并把泛型指定为Fruit
public class FruitAdapter extends ArrayAdapter<Fruit> {
    private int resourceId;

    //重写父类的一组构造函数,用来将context,ListView的子项布局和数据都传递进来
    public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
    super(context,textViewResourceId,objects);
        resourceId=textViewResourceId;
}
    //重写getView方法 传入三个参数 该视图在适配器中数据的位置,旧视图 和 parent
    //parent 表示此视图最终会被附加到父级视图
    public View getView(int position,View convertView,ViewGroup parent){
         Fruit fruit = getItem(position);
        //把position传入getItem()方法中来得到fruit实例
        View view= LayoutInflater.from(getContext()).inflate(resourceId,
                parent,false);
        //使用inflate方法去加载一个布局,用于ListView的每个Item的布局
        //inflate(layoutId, root, false )
        //第三个参数指定成false 表示只让我们在父布局中声明的layout属性生效,
        //但不为这个View添加父布局,因为一旦View有了父布局后就不能添加到ListView中
        ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
        TextView fruitName=(TextView)view.findViewById(R.id.fruit_name);
        //分别得到ImageView和TextView的实例
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());
        //设置显示的图像和名称
        return view;
    }
}

4.修改MainActivity中的代码

package com.example.kim.listview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private List<Fruit>fruitList = new ArrayList<>();
    //定义一个数组用于存放fruit构造函数

    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        //初始化水果数据
        FruitAdapter adapter= new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
        //给构造函数传入 context,ListView的子项布局,数据 3个参数
        ListView listView =(ListView)findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }
    private void initFruits(){
        for(int i=0;i<2;i++){
            Fruit apple =new Fruit("Apple",R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit mango =new Fruit("Mango",R.drawable.mango_pic);
            fruitList.add(mango);
            //.........省略N多水果
        }
    }
}

三.提升ListView的运行效率
①FruitAdapter中的getView()方法,每次都会将布局重新加载一遍 ListVIew快速滚动时会成为性能瓶颈

优化方法:修改getView()方法,利用getView()中的convertView参数,将加载好的布局进行缓存,便于之后调用。

    public View getView(int position,View convertView,ViewGroup parent){
         Fruit fruit = getItem(position);
        //把position传入getItem()方法中来得到fruit实例



         View view;
        if(convertView==null) {view = LayoutInflater.from(getContext()).inflate(resourceId,parent, false);
        }else {
            view = convertView;
        }
//优化的部分


        ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
        TextView fruitName=(TextView)view.findViewById(R.id.fruit_name);
        //分别得到ImageView和TextView的实例
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());
        //设置显示的图像和名称
        return view;
    }

②经过①的优化后,调用get()方法的时候虽然不会重复加载布局了,但是每次还是会调用View的findViewById()方法来获取控件实例

优化方法:新建一个内部类ViewHolder,当convertView为null,新建ViewHolder对象来存放控件实例,然后调用setTag()方法将ViewHolder对象放在View中,当convertView不为null时调用View中的getTag()将 ViewHolder取出,从而获取实例

public View getView(int position,View convertView,ViewGroup parent){
         Fruit fruit = getItem(position);
        //把position传入getItem()方法中来得到fruit实例
        View view;
        ViewHolder viewHolder;
        if(convertView==null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId,
                    parent, false);
            viewHolder = new ViewHolder();
            viewHolder.fruitImage=(ImageView)view.findViewById(R.id.fruit_image);
            viewHolder.fruitName=(TextView)view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder);//将viewHolder储存在View中
        }else {
            view = convertView;
            viewHolder=(ViewHolder)view.getTag();
        }
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());
        //设置显示的图像和名称
        return view;
    }
    //内部类ViewHolder,用于对实例缓存
    class ViewHolder{
        ImageView fruitImage;
        TextView fruitName;
    }

四、实现ListView的点击事件

    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        //初始化水果数据
        FruitAdapter adapter= new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
        //给构造函数传入 context,ListView的子项布局,数据 3个参数
        ListView listView =(ListView)findViewById(R.id.list_view);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
           public void onItemClick(AdapterView<?>parent,View view,int position,long id){
               //onItemClick()中传入4个参数,parent、view、position和id
               //分别对应父视图、当前视图、当前视图在父视图的位置、当前视图Id
               Fruit fruit = fruitList.get(position);
               //通过position参数判断用户点击了哪一个子项,从而获取到相应的水果

               //....此处省略响应事件代码
           }
        });
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值