[Android]-ListView & RecyclerView

ListView

滑动屏幕控件

<ListView
            android:id="@+id/lv_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
public class MainActivity extends AppCompatActivity {

    //测试数组
    private String[] data={"Apple","Banana","Orange","Lemon","Potato","Tomato","Gabbage",
            "Cocacola","Pepsi","Lemonade","Vegetable","Juice"};

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

        //创建适配器,用于向ListView中传递数据,ArrayAdapter类型的适配器可以通过泛型指定数据类型
        //第一个参数当前上下文,第二个参数是ListView子项布局的ID,第三个参数是要适配的数据
        //这里采用的simple_list_item_1是Android内置的布局文件,可用于显示一段TextView
        ArrayAdapter<String> adapter=new ArrayAdapter<String>(
                MainActivity.this, android.R.layout.simple_list_item_1,data);
        //绑定控件
        ListView listView=findViewById(R.id.lv_text);
        //传入适配器
        listView.setAdapter(adapter);
    }
}

定制界面

资源类

主要存储每个子项布局中需要用到的资源,图片ID,文本内容等等

package cn.ywrby.listviewtext;
//定义Fruit类,里边包含了ListView中每一行需要包含的所有元素
public class Fruit {
    private String text;
    private int imageID;


    public Fruit(String text, int imageID) {
        this.text = text;
        this.imageID = imageID;
    }

    public String getText() {
        return text;
    }

    public int getImageID() {
        return imageID;
    }
}

子项布局

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="wrap_content">

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

适配器

主要负责将数据类中的数据传入子项布局中

package cn.ywrby.listviewtext;

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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.List;

//定义适配器,负责向控件中传送数据
//继承自ArrayAdapter
public class FruitAdapter extends ArrayAdapter<Fruit> {

    private int resourceId;

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


    //重写getView方法,方法会在每个子项划入屏幕时被调用
    //第一个参数表示当前项的ID,第二个表示要绑定的控件,第三个表示该控件的父控件
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Fruit fruit=getItem(position);   //获取当前需要写入的数据类
        View view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);  //获取当前要操作控件
        ImageView imageView=view.findViewById(R.id.fruit_image);
        TextView textView=view.findViewById(R.id.fruit_id);
        imageView.setImageResource(fruit.getImageID());  //写入图片数据
        textView.setText(fruit.getText());  //文本数据
        return view;  //返回已经操作完成的控件
    }
}

MainActivity

package cn.ywrby.listviewtext;

import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

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

public class MainActivity extends AppCompatActivity {

    //测试数组
    private List<Fruit> 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=findViewById(R.id.lv_text);
        //传入适配器
        listView.setAdapter(adapter);
    }

    //初始化数组内容
    private void initFruits(){
        for(int i=0;i<5;i++){
            Fruit apple=new Fruit("Apple",R.drawable.apple);
            fruitList.add(apple);
            Fruit lemon=new Fruit("Lemon",R.drawable.lemon);
            fruitList.add(lemon);
            Fruit banana=new Fruit("Banana",R.drawable.banana);
            fruitList.add(banana);
            Fruit cola=new Fruit("CokeCola",R.drawable.cola);
            fruitList.add(cola);
        }
    }
}

YXNEjS.png

性能优化

如果不进行任何性能优化,我们每次有子项布局划入屏幕都会重新加载资源,哪怕它刚刚已经被加载过了

所以,为了避免这种问题,可以对其进行优化

在每次重新加载控件前,都会对第二个参数进行一次判断,第二个参数是将之前的参数进行缓存,以方便以后重用,如果这个参数不为空,就可以省去加载控件的时间,直接复用以前的布局

@NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Fruit fruit=getItem(position);   //获取当前需要写入的数据类
        View view;
        if(convertView==null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        }
        else {
            view=convertView;
        }
        ImageView imageView=view.findViewById(R.id.fruit_image);
        TextView textView=view.findViewById(R.id.fruit_id);
        imageView.setImageResource(fruit.getImageID());  //写入图片数据
        textView.setText(fruit.getText());  //文本数据
        return view;  //返回已经操作完成的控件
    }

上述方法优化了布局加载时间,但每次调用findViewByID还是会重新获取一次控件实例,所以还可以借助ViewHolder继续优化ListView性能

ListView点击事件

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

RecyclerView

重写适配器类

package cn.ywrby.recyclerviewtext;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

    //存储每个子布局所需资源的集合
    private List<Fruit> mFruitList;

    //内部类ViewHolder,缓存布局方式
    static class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imageView;
        private TextView textView;
        //构造方法
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            imageView=itemView.findViewById(R.id.fruit_image);
            textView=itemView.findViewById(R.id.fruit_id);
        }
    }

    //构造方法
    public FruitAdapter(List<Fruit> mFruitList) {
        this.mFruitList = mFruitList;
    }


    //onCreateViewHolder负责创建ViewHolder
    @NonNull
    @Override
    public FruitAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //获取布局方式
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
        ViewHolder holder=new ViewHolder(view);  //创建ViewHolder对象
        return holder;
    }

    //将资源与对应的子布局绑定
    //在每次对应子布局进入屏幕时调用
    @Override
    public void onBindViewHolder(@NonNull FruitAdapter.ViewHolder holder, int position) {
        Fruit fruit=mFruitList.get(position);  //获取对应位置资源
        holder.imageView.setImageResource(fruit.getImageID());  //将对应资源写入
        holder.textView.setText(fruit.getText());
    }

    //长度
    @Override
    public int getItemCount() {
        return mFruitList.size();
    }


}

MainActivity

public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        initFruits();  //初始化资源集合
        RecyclerView recyclerView=findViewById(R.id.recycler_view);  //找到RecyclerView对象
        LinearLayoutManager layoutManager=new LinearLayoutManager(this);  //表示RecyclerView对象的布局方式,这里采用线性布局
        recyclerView.setLayoutManager(layoutManager);  //绑定布局方式
        FruitAdapter fruitAdapter=new FruitAdapter(fruitList);
        recyclerView.setAdapter(fruitAdapter);  //将资源导入

    }

    //初始化数组内容
    private void initFruits(){
        for(int i=0;i<5;i++){
            Fruit apple=new Fruit("Apple",R.drawable.apple);
            fruitList.add(apple);
            Fruit lemon=new Fruit("Lemon",R.drawable.lemon);
            fruitList.add(lemon);
            Fruit banana=new Fruit("Banana",R.drawable.banana);
            fruitList.add(banana);
            Fruit cola=new Fruit("CokeCola",R.drawable.cola);
            fruitList.add(cola);
        }
    }
}

RecyclerView实现横向滚动

修改fruit_item

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

    <ImageView
            android:id="@+id/fruit_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
    />
    <TextView
            android:id="@+id/fruit_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"/>
</LinearLayout>

修改MainActivity中的布局方式

RecyclerView recyclerView=findViewById(R.id.recycler_view);  //找到RecyclerView对象
LinearLayoutManager layoutManager=new LinearLayoutManager(this);  //表示RecyclerView对象的布局方式,这里采用线性布局
recyclerView.setLayoutManager(layoutManager);  //绑定布局方式
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);  //设置布局排列方式,默认纵向,这里设置为横向
同样的通过设置布局方式,还可以很轻松的设置为瀑布流布局等排列方式

RecyclerView点击事件

RecyclerView并不提供类似ListView中setOnItemClickListener的注册监听器方法,每个监听器需要手动绑定,并且可以轻松控制如何绑定,是绑定整个子布局还是其中某个控件,都可以轻松实现

package cn.ywrby.recyclerviewtext;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

    //存储每个子布局所需资源的集合
    private List<Fruit> mFruitList;

    //内部类ViewHolder,缓存布局方式
    static class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imageView;
        private TextView textView;
        private View fruitView;
        //构造方法
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            fruitView=itemView;
            imageView=itemView.findViewById(R.id.fruit_image);
            textView=itemView.findViewById(R.id.fruit_id);
        }
    }

    //构造方法
    public FruitAdapter(List<Fruit> mFruitList) {
        this.mFruitList = mFruitList;
    }


    //onCreateViewHolder负责创建ViewHolder
    @NonNull
    @Override
    public FruitAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //获取布局方式
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
        final ViewHolder holder=new ViewHolder(view);  //创建ViewHolder对象

        //绑定整个布局
        holder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position=holder.getAdapterPosition();
                Fruit fruit=mFruitList.get(position);
                Toast.makeText(v.getContext(),"you clicked view "+fruit.getText(),Toast.LENGTH_SHORT).show();
            }
        });

        //绑定图片控件
        holder.imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position=holder.getAdapterPosition();
                Fruit fruit=mFruitList.get(position);
                Toast.makeText(v.getContext(),"you clicked image "+fruit.getText(),Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

    //将资源与对应的子布局绑定
    //在每次对应子布局进入屏幕时调用
    @Override
    public void onBindViewHolder(@NonNull FruitAdapter.ViewHolder holder, int position) {
        Fruit fruit=mFruitList.get(position);  //获取对应位置资源
        holder.imageView.setImageResource(fruit.getImageID());  //将对应资源写入
        holder.textView.setText(fruit.getText());
    }

    //长度
    @Override
    public int getItemCount() {
        return mFruitList.size();
    }


}

上文中通过修改内部类成员变量以及onCreateViewHolder实现了每个布局的点击事件,并且是分别为图片和整个子布局添加响应事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值