11.Android开发笔记:ListView

0.ListView概述

1.只能做纵向滚动,不能做横向滚动
2.需要做性能优化

1.ListView 简单用法

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

</LinearLayout>

public class MainActivity extends AppCompatActivity {

    private List<String> listDatas = Arrays.asList("Apple", "Banana", "Orange", "Watermelon",
                "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango"
                , "Apple", "Banana"
                , "Orange", "Watermelon"
                , "Pear", "Grape",
                "Pineapple"
                , "Strawberry", "Cherry", "Mango");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //ArrayAdapter的构造函数传入3个数据:1是Context 传入当前的上下文,2是ListView子项布局的ID,3是要适配的数据
        //android.R.layout.simple_list_item_1,listDatas是内置的ListViewItem
        ArrayAdapter<String> dapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1,listDatas);
        ListView listView =  findViewById(R.id.m_listView1);
        listView.setAdapter(dapter);

    }
}

2.自定义ListViewItem

1-定义布局文件 fruit_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal" android:layout_width="match_parent"
  android:layout_height="wrap_content">

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

2-定义Fruit类:


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

    private int imageId;
    private String name;

    public int getImageId() {
        return imageId;
    }

    public void setImageId(int imageId) {
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

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

3-定义Adapter: FruitAdapter extends ArrayAdapter


public class FruitAdapter extends ArrayAdapter<Fruit> {

    private int resourceId;

    public FruitAdapter(@NonNull Context context, int textViewResourceId, List<Fruit> objects) {
        super(context, textViewResourceId, objects);
        resourceId = textViewResourceId;
    }

    /**
     * 每个子项被滚动到屏幕时调用
     * */
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        Fruit fruit = getItem(position);

        View view = LayoutInflater.from(getContext()) //获得LayoutInflater对象
                .inflate(resourceId ,parent ,false); //根据布局id把这个布局加载成一个View并返回

        ImageView fruitImage = view.findViewById(R.id.fruit_image);
        TextView fruitName = view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());

        return view;
    }
}

4-加载数据


public class MainActivity extends AppCompatActivity {

/*    private List<String> listDatas = Arrays.asList("Apple", "Banana", "Orange", "Watermelon",
                "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango"
                , "Apple", "Banana"
                , "Orange", "Watermelon"
                , "Pear", "Grape",
                "Pineapple"
                , "Strawberry", "Cherry", "Mango");*/

    private List<Fruit> fruits = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

/*        //ArrayAdapter的构造函数传入3个数据:
        // 1是Context 传入当前的上下文
        // ,2是ListView子项布局的ID
        // ,3是要适配的数据
        //android.R.layout.simple_list_item_1,listDatas是内置的
        ArrayAdapter<String> dapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1,listDatas);
        ListView listView =  findViewById(R.id.m_listView1);
        listView.setAdapter(dapter);*/

        InitFruits();
        FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruits);
        ListView listView = findViewById(R.id.m_listView1);
        listView.setAdapter(adapter);
    }

    private  void InitFruits(){

        for (int i= 0; i < 10 ; i++){
            Fruit taozi = new Fruit(R.drawable.taozi, "桃子");
            fruits.add(taozi);

            Fruit putao = new Fruit(R.drawable.putao, "葡萄");
            fruits.add(putao);

            Fruit huolongguo = new Fruit(R.drawable.huolongguo, "火龙果");
            fruits.add(huolongguo);

            Fruit lamei = new Fruit(R.drawable.lanmei, "蓝莓");
            fruits.add(lamei);

            Fruit xiguang = new Fruit(R.drawable.xigua, "西瓜");
            fruits.add(xiguang);
        }
    }
}

效果:

3.优化ListView性能

1.getView()方法中,每次都将布局重新加载了一遍,当ListView快速滚动的时候,这就会成为性能的瓶颈。
convertView参数,这个参数用于将之前加载好的布局进行缓存,以便之后可以进行重用。
2.调用View 的 findViewById()方法来获取一次控件的实例。借助一个ViewHolder来对这部分性能进行优化


public class FruitAdapter extends ArrayAdapter<Fruit> {

    private int resourceId;

    public FruitAdapter(@NonNull Context context, int textViewResourceId, List<Fruit> objects) {
        super(context, textViewResourceId, objects);
        resourceId = textViewResourceId;
    }

    /**
     * 每个子项被滚动到屏幕时调用
     */
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        Fruit fruit = getItem(position);
/*        View view = LayoutInflater.from(getContext()) //获得LayoutInflater对象
                .inflate(resourceId ,parent ,false); //根据布局id把这个布局加载成一个View并返回*/

        /****************************优化ListView运行效率********************************************************
         1.getView()方法中,每次都将布局重新加载了一遍,当ListView快速滚动的时候,这就会成为性能的瓶颈。
           convertView参数,这个参数用于将之前加载好的布局进行缓存,以便之后可以进行重用。

         2.调用View 的 findViewById()方法来获取一次控件的实例。借助一个ViewHolder来对这部分性能进行优化
       *********************************************************************************************************/

        View view = null;
        ViewHolder viewHolder;

        if (null == convertView) {
            view = LayoutInflater.from(getContext()) //获得LayoutInflater对象
                    .inflate(resourceId, parent, false); //根据布局id把这个布局加载成一个View并返回

            viewHolder = new ViewHolder();
            viewHolder.fruitImage  = view.findViewById(R.id.fruit_image);
            viewHolder.fruitName = view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder);  //将ViewHolder存储在View中

        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag(); //从View中获取ViewHolder
        }
        
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());

        return view;
    }

    class ViewHolder{
        ImageView fruitImage;
        TextView fruitName;
    }
}


4.ListView的点击事件

        //ListView 子项点击事件
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Fruit fruit = fruits.get(position);
                Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_LONG).show();

/*              TextView fruitName =  view.findViewById(R.id.fruit_name);
                Toast.makeText(MainActivity.this, fruitName.getText().toString(), Toast.LENGTH_LONG).show();*/
            }
        });

在点击事件中获取Fruit的数据


 //ListView 子项点击事件
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Adapter adapter = parent.getAdapter();
                Fruit fruit = (Fruit) adapter.getItem(position);
                Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });

5.其它

ListView 用法大全、性能优化以及功能拓展
Android 性能优化篇之--复杂listView高效渲染

原文地址:https://www.cnblogs.com/easy5weikai/p/12466412.html