ListView:ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕
一、简单的做一个ListView
1、在布局中引用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"
    >
<ListView
    android:id="@+id/list_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />


</LinearLayout>

2、在活动中显示ListView
说明:(1)ListView中是展示大量数据的,所以要事先将数据准备好。数据可以是可以从网上下载的也可以是数据库中的。视具体情况而定。这里为了展示,就建一个数组data来存放要展示在ListView上的数据
(2)数组中的数据不能直接传给ListView,所以需要借助一个适配器完成。(其实别的地方数据传进ListView也需要适配器,适配器是个接口,作用就是把数据传进ListView。当然数据存放的地方不同传进的实现类也不同。这里是数组,所以用ArrayAdapter这个实现类)。(后面会说)

public class MainActivity extends AppCompatActivity {
    private String[] data={"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<String>adapter=new ArrayAdapter<String>(
                MainActivity.this,android.R.layout.simple_list_item_1,data);
        ListView listView=(ListView)findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }
}

说明:
(1)适配器实现类通过泛型来指定要适配的数据类型
(2)构造函数三个参数
第一个参数:当前上下文
第二个参数:ListView中子项的布局(就是子项该怎么显示)。这里没有为子专门定义一个布局,而是直接用了android.R.layout.simple_list_item_1。它是Android内置的一个布局文件,里面只有一个TextView,可用简单地显示一段文本。
第三个参数:要适配的数据(即要传进ListView中地数据)
这样一个最简单地ListView就构建好了。
Android中控件——ListView
这里可能会猜想:ArrayAdapter是怎样按照顺序把数组中的数据取出来送到ListView中地,也没有用到数据元素地id。我想这就是ArrayAdapter这个适配器内置封装地功能吧。要是我们自己写适配器,那一定是要把适配的具体操作功能都写出来的。
二、完善ListView
目标:1、不在把数据放在数组中,不让数据只有一个简单地名字,二十既有名字又有图片,那么就要定义一个Fruits类。并且把数据放在一个List容器中
2、既然现在数据已经不是仅仅有名字了,所以就不能再用Android自带地那个子项布局了,所以要自己创建一个子项布局用于显示水果的名字和图片。
3、既然数据不存在数组中了,就不能再使用ArrayAdapter这个适配器了,所以要自己创建一个适配器。
具体步骤
1、定义一个水果类(作为适配器要适配的类型)

public class Fruits {
    private String name;
    private int imageId;
    public Fruits(String name,int imageId )
    {
        this.name=name;
        this.imageId=imageId;
    }
    public String getName()
    {
        return name;
    }
    public int imageId()
    {
        return imageId;
    }
}

2、创建一个用于显示子项的布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        />

</LinearLayout>

注意这个子项布局的id是fruit_item(一会儿适配器会用)
3、接下来就是很重要的创建适配器的环节
这里包括构造参数传子项布局的id,子项滚动到屏幕内显示照片的名字的方法。这些在ArrayAdapter的里面都是封装好的,但是这个新建的适配器就需要要我们自己完成。

public class FruitAdapter extends ArrayAdapter<Fruits>{
    private int resourceId;
    public FruitAdapter(Context context,int textViewResourceId,List<Fruits> objects){
        super(context,textViewResourceId,objects);
        resourceId=textViewResourceId;
    }

    @Override
    public View getView(int position,  View convertView, ViewGroup parent) {
        Fruits fruit=getItem(position);
        View view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        ImageView fruitImage=(ImageView)view.findViewById(R.id.fruit_image);
        TextView fruitName=(TextView) view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.imageId());
        fruitName.setText(fruit.getName());
        return view;
    }
}

(1)构造函数,同样第一个是上下文,第二个是子项布局id(这里把布局都看成int型),第三个是要是要适配的数据(由于一会要传进来List,所以提前将第三个参数设为List型)
(2)重写getview函数,这个方法是每个子项被滚动到屏幕内的时候会被调用。
在getView方法后中,首先获得当前位置的数据。
然后引入子项布局,分别获取两个实例。然后分别调用函数显示布局和文字,最后返回布局
4、最后在主活动中引入适配器,初始化数据。

public class MainActivity extends AppCompatActivity {
                  "Pear","Grape","Pineapple", "Strawberry","Cherry","Mango"};
    private List<Fruits> fruitList=new ArrayList<>();

    @Override
    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);
        ListView listView=(ListView)findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }
    private void initFruits(){
        for(int i=0;i<2;i++)
        {
            Fruits apple=new Fruits("Apple",R.drawable.apple_pic);
            fruitList.add(apple);
            Fruits banana=new Fruits("Banana",R.drawable.banana_pic);
            fruitList.add(banana);
            Fruits orange=new Fruits("Apple",R.drawable.orange_pic);
            fruitList.add(orange);
            Fruits watermelon=new Fruits("Watermelon",R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruits pear=new Fruits("Pear",R.drawable.pear_pic);
            fruitList.add(pear);
            Fruits grape=new Fruits("Grape",R.drawable.grape_pic);
            fruitList.add(grape);
            Fruits pineapple=new Fruits(" Pineapple",R.drawable. pineapple_pic);
            fruitList.add( pineapple);
            Fruits strawberry=new Fruits("Strawberry",R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruits cherry=new Fruits("Cherry",R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruits mango=new Fruits("Mango",R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }
}

(1)适配器的实例传进去那三个参数的实例
(2)ListView的实例是在主活动中实例化的
(3)子项中的图片还有文字实例是在适配器中实例化的
三、优化ListView
要优化的地方有两点:
1、因为子项每一次滚动到屏幕的时侯都要用到getView()函数,这样就会导致布局被多次载入。所以这里利用getView()的另一个参数convertView(这个参数用来将之前缓存好的布局进行缓存,为了以后的重用)
2、解决了第一个问题,每一次还是会调用findViewById来获取控件的实例,所以这里利用一个内部类ViewHolder,创建这个类的对象,用于对控件实例的缓存。优化后的适配器的代码如下

@Override
    public View getView(int position,  View convertView, ViewGroup parent) {
        Fruits fruit=getItem(position);
        ViewHolder viewHolder;
        View view;
        
        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);
        }else{
            view=convertView;
            viewHolder=(ViewHolder) view.getTag();
        }
        viewHolder.fruitImage.setImageResource(fruit.imageId());
        viewHolder.fruitName.setText(fruit.getName());
        return view;
    }
    class ViewHolder{
        ImageView fruitImage;
        TextView fruitName;
    }

(1)判断convertView 是否为空,如果是的话,引入布局,创建实例,并把实例利用setTag()函数缓存起来
(2)如果convertView不是空,则直接让布局等于convertView。并且通过getTag()来取出缓存
四、ListView 的点击事件

listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Fruits fruit=fruitList.get(position);
                Toast.makeText(MainActivity.this,fruit.getName(),Toast.LENGTH_SHORT).show();
            }
        });

(1)AdapterView:列表形式显示数据
(2)public void onItemClick(AdapterView<?> parent, View view, int position, long id)
固定写法:可以通过position参数判断出用户带带点击是哪一个子项,然后得到响应的水果,并显示出来名字。

相关文章:

  • 2022-01-21
  • 2021-12-27
  • 2022-12-23
  • 2022-12-23
  • 2021-11-22
  • 2021-08-29
  • 2021-07-05
  • 2021-12-16
猜你喜欢
  • 2022-01-19
  • 2021-12-24
  • 2021-04-28
  • 2021-09-04
  • 2021-04-18
  • 2021-07-22
相关资源
相似解决方案