IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android ListView和RecyclerView -> 正文阅读

[移动开发]Android ListView和RecyclerView

1.ListView

1.1ListView的简单使用

listView在开发中经常用到,首先看一下listView的实现效果

  1. 新建activity_main.xml和list_item.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@color/white"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?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">

    <TextView
        android:id="@+id/tv"
        android:textSize="20sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

在activity_main中添加ListView控件,list_item就是列表中每一项的布局(只添加了一个Textview,可以通过修改list_item来定制不同的ListView界面)
2. 新建一个JavaBean类,作为适配器的适配类型

public class Bean {
    private String name;

    public String getName() {
        return name;
    }

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

在Bean类中只有一个属性name,用于设置textView的文本
3. 新建一个MyAdapter继承自BaseAdapter

public class MyAdapter extends BaseAdapter {

    private List<Bean> data;
    private Context mContext;

    public MyAdapter(List<Bean> data, Context mContext) {
        this.data = data;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView= LayoutInflater.from(mContext).inflate(R.layout.list_item,parent,false);
        TextView textView=convertView.findViewById(R.id.tv);
        textView.setText(data.get(position).getName());
        return convertView;
    }
}

在MyAdapter中重写了父类的构造方法,用于将context(上下文)和ListView子项的数据传递进来;然后又重写了getView()方法,这个方法是在listView中每个子项滚动到屏幕中时就会调用,在这个方法中通过LayoutInflater.from()方法加载listView子项的布局,并且设置textView需要显示的文本内容。
4. 最后在MainActivity中修改代码,通过setAdapter()方法将创建好的适配器对象传递进去,建立ListView和数据之间的关联。

public class MainActivity extends AppCompatActivity {

    private List<Bean> data=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        ListView listView=findViewById(R.id.listView);
        listView.setAdapter(new MyAdapter(data,this));
    }
}

当然这个只显示一个TextView的ListView比较简单,可以更为简单的实现(直接使用ArrayAdapter)
修改MainActivity中的代码:

public class MainActivity extends AppCompatActivity {

    private List<Bean> data=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        ArrayAdapter<Bean> adapter=new ArrayAdapter<Bean>(this,android.R.layout.simple_list_item_1,data);
        ListView listView=findViewById(R.id.listView);
        listView.setAdapter(adapter);
    }
}

这里的android.R.layout.simple_list_item_1是Android内置的一个布局文件,里面只有一个Textview,当然也可以使用我们创建的list_item.xml,最后实现的效果是相同的。

1.2 ListView的优化

我们可以分析一下BaseAdapter中的getView()方法,每次都要重新绘制子项view和通过findViewById()方法来获取控件。

  1. 通过对getView()方法的观察,convertView这个参数我们只是粗略的使用,并没有发挥它的效果,convertView这个参数时用于将之前加载好的布局进行缓存,这样我们就可以通过判断convertView是否为null,如果为null,在调用LayoutInflater来进行绘制View,如果不为null,就可以直接复用。
public class MyAdapter extends BaseAdapter {

    private List<Bean> data;
    private Context mContext;

    public MyAdapter(List<Bean> data, Context mContext) {
        this.data = data;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        MyViewHolder viewHolder;
        if(convertView ==null){
            convertView=LayoutInflater.from(mContext).inflate(R.layout.list_item,parent,false);
            viewHolder=new MyViewHolder();
            viewHolder.textView=convertView.findViewById(R.id.tv);
            convertView.setTag(viewHolder);
        }else{
            viewHolder= (MyViewHolder) convertView.getTag();
        }
        viewHolder.textView.setText(data.get(position).getName());
        return convertView;
    }

   class MyViewHolder{
        TextView textView;
   }
}

2.在MyAdapter中我们新建了一个MyViewHolder类(见名思意,就是view的持有者),用于对控件的实例进行缓存,当convertView 为null时,创建一个viewHolder对象,并将控件的实例都存放在该对象中,然后通过view.setTag()方法,将viewHolder对象存储在convertView 中,当convertView 不为null时,通过view的getTag()方法取出viewHolder对象,这样就不用每次都通过findViewById来获取控件的实例了,同时也大大提高的ListView的运行效率。

1.3 ListView的点击事件

ListView的点击事件主要通过setOnItemClickListener方法实现

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        ListView listView=findViewById(R.id.listView);
        listView.setAdapter(new MyAdapter(data,this));
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this,data.get(position).getName(),Toast.LENGTH_LONG)
                .show();
            }
        });
    }

当我们进行点击的时候通过position判断出我们点击的是哪一项,这里用Toast进行显示。

2.RecyclerView

上面介绍了ListView的简单使用和性能优化,接下来介绍一下一个更为强大的控件RecyclerView,并且Android官方也更加推荐使用RecyclerView。

2.1 RecyclerView的简单使用
  1. 将上方activity_main中的listView替换为RecyclerView。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
  1. 修改MyAdapter继承自RecyclerView.Adapter,并且新建一个内部类ViewHolder继承自RecyclerView.ViewHolder
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<Bean> data;
    private Context mContext;

    public MyAdapter(List<Bean> data, Context mContext) {
        this.data = data;
        this.mContext = mContext;
    }

    @NonNull
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(mContext).inflate(R.layout.recycler_item,parent,false);
        ViewHolder holder=new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            textView=itemView.findViewById(R.id.recycler_text);
        }
    }
}

重写的三个方法:

  1. onCreateViewHolder:这个方法是用于创建ViewHolder实例的,在这个方法中通过LayoutInflater绘制recycler_item(recyclerview的item布局),然后创建viewHolder实例并且将绘制的view加载到viewholder中去。
  2. onBindViewHolder:这个方法就类似于ListView中的getView()方法,会在每个item滚动到屏幕中时执行,通过position得到当前项的数据,然后在设置到viewHolder保存的控件实例中
  3. getItemCount:返回recyclerView子项的个数
  1. 修改MainActivity中的代码
public class MainActivity extends AppCompatActivity {

    private List<Bean> data=new ArrayList<>();
    private RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        mRecyclerView=(RecyclerView) findViewById(R.id.recyclerView);
        LinearLayoutManager manager=new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(manager);
        mRecyclerView.setAdapter(new MyAdapter(data,this));
    }
}

LayoutManager用于指定RecyclerView的布局,我们在这里使用的是LinearLayoutManager (线性布局管理器),所以实现效果和ListView相同。
recyclerview

2.2 实现网格布局和瀑布流布局
  1. 网格布局其实非常简单,只要改变我们所使用的布局管理器就行了,这里使用GridLayoutManager
    修改MainActivity中的代码:
 mRecyclerView=(RecyclerView) findViewById(R.id.recyclerView);
 		//第二个参数代表网格布局用几列进行显示
        GridLayoutManager manager=new GridLayoutManager(this,4);
        mRecyclerView.setLayoutManager(manager);
        mRecyclerView.setAdapter(new MyAdapter(data,this));

在这里插入图片描述
2. 瀑布流布局也是如此

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Random random=new Random();
            int length=random.nextInt(20)+1;
            StringBuilder builder=new StringBuilder();
            for(int j=0;j<length;j++){
                builder.append("安卓,");
            }
            Bean bean=new Bean();
            bean.setName(builder.toString()+"---"+i);
            data.add(bean);
        }
        mRecyclerView=(RecyclerView) findViewById(R.id.recyclerView);
        StaggeredGridLayoutManager manager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(manager);
        mRecyclerView.setAdapter(new MyAdapter(data,this));
    }
}

在这里使用了StaggeredGridLayoutManager ,两个参数分别是:列数;排列方向。
为了更直观的可以看出瀑布流和网格布局的差别(需要每个子项的高度不一样才能看出来),在这里使用了random函数,随机的将参数中传入的字符串重复N遍。
在这里插入图片描述

2.3 点击事件

RecyclerView和ListView不同,RecyclerView没有提供Item的点击事件,所以需要我们自己进行设置。

  1. 在onBindViewHolder方法中通过setOnClickListener实现
    @Override
    public void onBindViewHolder(@NonNull @org.jetbrains.annotations.NotNull MyAdapter.MyViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context,"你点击了第"+position+"项",Toast.LENGTH_SHORT).show();
            }
        });
        holder.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context,"你点击了第"+position+"项",Toast.LENGTH_SHORT).show();
            }
        });
    }

通过 holder.itemView设置的点击事件是RecyclerView单个子项整体的点击事件,而通过holder.textView设置的点击事件是Item子项的点击事件;比如list_item中有button和textView时,可以通过这个方法分别设置button和textView的点击事件。
2. 通过接口回调的方式进行实现
(1)在MyAdapter中定义一个接口,专门用于设置点击事件

public interface OnItemListener{
        void onItemClick(View view,int position);
    }

(2)定义这个接口的set方法并且声明变量,便于调用

private OnItemListener mListener;

    public void setOnItemClickListener(OnItemListener listener){
        this.mListener=listener;
    }

(3)在onBindViewHolder中设置点击事件

    @Override
    public void onBindViewHolder(@NonNull @org.jetbrains.annotations.NotNull MyAdapter.MyViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
        holder.imageView.setImageResource(data.get(position).getImageId());
        //根布局的点击事件
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mListener!=null){//判断是否设置了监听
                    //通过holder.getAdapterPosition()获取当前item的位置
                    mListener.onItemClick(holder.itemView, holder.getAdapterPosition());
                    
                }

            }
        });
        //item子view的点击事件
        holder.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mListener!=null){//判断是否设置了监听
                    //通过holder.getAdapterPosition()获取当前item的位置
                    mListener.onItemClick(holder.textView, holder.getAdapterPosition());

                }
            }
        });
    }

(4)在MainActivity中设置点击事件的具体效果(通过调用adapter中的setOnItemClickListener)

 myAdapter.setOnItemClickListener(new MyAdapter.OnItemListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this,"点击了第"+position+"项",Toast.LENGTH_SHORT).show();
            }
        });

这样就可以实现RecyclerView的点击事件了。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-29 13:09:42  更:2021-10-29 13:11:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:09:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码