Android高级UI之Material Design下的RecyclerView与ListView的区别与用法(详解)

引言:大家在刷图片或者视频等大量数据当手机屏幕一下子填充不了的时候,是不是可以左刷刷有刷刷上刷刷下刷刷呢?让我们来了解一下这些功能的简单实现吧。

主题:ListView与RecyclerView的基本用法与区别

一、ListView的基本用法,
1.在所需的layout文件里添加ListView控件
2.新建一个layout文件,为ListView填充布局
3.新建一个Bean类,填充所需要的布局数据,比如图片资源id等。
4.新建一个适配器(ListView的数据是要靠适配器来提供的),继承BaseAdapter或者ArraysAdapter(有很多款适配器),然后为适配器添加一个构造函数,最好是这种(Context context,LIst data),便于将数据和上下文的环境传到适配器中
5.重写Adapter中的方法然后进行适配数据
6.为ListView设置上述的适配器就可以了

代码如下:

二.java代码:
1.Bean类–提供数据

public class Bean {
    public Bean(String name, int id){
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    private String name;
     private int id;

}

2.适配器,配置listview功能的类

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

import java.util.List;
import java.util.logging.Handler;

public class MyListViewAdapter extends BaseAdapter {

    List<Bean> data;
    Context context;


    MyListViewAdapter(Context context,List<Bean> data){
        this.data = data;
        this.context = context;
    }

    @Override
    public int getCount() {
        //整个Activity要展现的item数目
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        //获取该位置的布局item
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        //获取该位置的布局item的id
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //屏幕出现布局的地方调用
        ViewHolder viewHolder;
        if(convertView == null){
            viewHolder = new ViewHolder();
            convertView = LayoutInflater.from(context).inflate(R.layout.listview_item, parent, false);
            viewHolder.imageView = convertView.findViewById(R.id.iv);
            viewHolder.textView = convertView.findViewById(R.id.tv);
            convertView.setTag(viewHolder);
        }
        else viewHolder = (ViewHolder) convertView.getTag();
        viewHolder.textView.setText(data.get(position).getName());
        viewHolder.imageView.setImageResource(data.get(position).getId());

        return convertView;
        //convertView是放缓存布局的
    }
    public class ViewHolder{
        TextView textView;
        ImageView imageView;
    }
}

每个方法的功能代码里面有注释,
注:ViewHolder是为了解决动态加载页面以及findViewbyId调用时 时间性能上的消耗,利用了convertView来存放缓存的数据所放成员变量是listview布局文件里的控件

3.Activity主方法:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.ListView;

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

public class MainActivity extends AppCompatActivity {
    List<Bean> data = new ArrayList<Bean>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i = 0; i < 4; i++){
            Bean bean1 = new Bean("aDog",R.drawable.adog);
            Bean bean2 = new Bean("bDog",R.drawable.bdog);
            Bean bean3 = new Bean("cDog",R.drawable.cdog);
            Bean bean4 = new Bean("dDog",R.drawable.ddog);
            Bean bean5 = new Bean("eDog",R.drawable.edog);
            Bean bean6 = new Bean("aCat",R.drawable.acat);
            Bean bean7 = new Bean("bCat",R.drawable.bcat);
            Bean bean8 = new Bean("cCat",R.drawable.ccat);
            Bean bean9 = new Bean("dCat",R.drawable.dcat);
            Bean bean10 = new Bean("eCat",R.drawable.ecat);
            Bean bean11 = new Bean("fCat",R.drawable.fcat);
            data.add(bean1);
            data.add(bean2);
            data.add(bean3);
            data.add(bean4);
            data.add(bean5);
            data.add(bean6);
            data.add(bean7);
            data.add(bean8);
            data.add(bean9);
            data.add(bean10);
            data.add(bean11);
        }
        ListView listView = findViewById(R.id.lv);
        MyListViewAdapter adapter = new MyListViewAdapter(this, data);
        listView.setAdapter(adapter);
    }
}

其中最关键的是这三行代码:

        ListView listView = findViewById(R.id.lv);
        MyListViewAdapter adapter = new MyListViewAdapter(this, data);
        listView.setAdapter(adapter);

行了,在不设置监听的状态下跑一下程序:

在这里插入图片描述
成功之后就可以上下拉动数据。
最后谈一下ListView的监听功能:
ListView有自己专属的listener—setOnItemClickListener():
代码如下:

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.e("MainActivity", "onItemClick: " + "I am " + data.get(position).getName());
            }
        });

重写了onItemClick()方法后可以自定义逻辑
这里只做简单打印

接着重新运行然后点击任意Item后的效果:
在这里插入图片描述
二.RecyclerView的基本用法

RecyclerView是官方更为推荐的控件,原因它比ListView更为灵活,它将布局的layout由LayoutManager去管理,有多样的呈现方式。而ListView的layout就只能在配置布局中定义

话不多说,代码开撸,直接感受一下它的用法:
一:操作流程步骤如下:
1.添加依赖
2.在所需要的layout文件中使用RecyclerView
3.自定义layout布局文件来填充RecyclerView的数据
4.新建Bean类,放着资源id
5.新建Java类 Adapter继承至RecyclerViewAdapter
6.在Adapter中配置好Bean数据以及数据的展现逻辑
7.添加一个LayoutManager,根据所需要的方式选择layout

下面直接来撸代码:
1.首先是Adapter的代码:

package com.coolweather.list_recycler_fragment;

import android.content.Context;
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 MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {
    List<Bean> data;
    Context context;
    public MyRecyclerViewAdapter(Context context, List<Bean> data){
        this.data = data;
        this.context = context;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //传入配置的布局文件来创建ViewHolder
        //注意:RecyclerView没有特定的监听功能,但是可以任意为所在布局文件的控件设置监听功能,如下:
        final MyViewHolder myViewHolder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.listview_item, parent, false));
        myViewHolder.imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(v.getContext(),"You click "+ data.get(myViewHolder.getAdapterPosition()).getName(),Toast.LENGTH_SHORT).show();
            }
        });
        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        //为所在位置的每一个item设置展现的资源
          holder.textView.setText(data.get(position).getName());
          holder.imageView.setImageResource(data.get(position).getId());
//          holder.imageView.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                Toast.makeText(v.getContext(),"You click "+ data.get(holder.getAdapterPosition()).getName(),Toast.LENGTH_SHORT).show();
//            }
//        });     //在此方法中设立监听功能就要为将方法参数改为 final MyViewHolder holder

    }

    @Override
    public int getItemCount() {
        //RecyclerView要展现多少数据
        return data.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder{
        //这个类是必要的,也一定要继承自RecyclerView.ViewHolder
        TextView textView;
        ImageView imageView;

        public MyViewHolder(@NonNull View itemView) {
            //ViewHolder的构造方法,参数是传入的布局文件
            super(itemView);
            textView = itemView.findViewById(R.id.tv);
            imageView = itemView.findViewById(R.id.iv);
//            imageView.setOnClickListener(new View.OnClickListener() {
//                @Override
//                public void onClick(View v) {
//                    Toast.makeText(v.getContext(),"You click "+ data.get(getAdapterPosition()).getName(),Toast.LENGTH_SHORT).show();
//                }
//            });
        }
    }
}

这里重写的方法与ListView不同,每一个方法的作用都写在注释里面了;

接下来是主代码:

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv);
        MyRecyclerViewAdapter myRecyclerViewAdapter = new MyRecyclerViewAdapter(this,data);
//        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//        GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(myRecyclerViewAdapter);

这里与Listview大有不同的就是多了比ListView多了GridLayout(网格布局,参数的数字是代表几列) 与 StaggerdGridLayout(瀑布流布局,参数的数字也是代表几列),而且这里可以灵活的改变orientation的布局方式,比如HORIZONTAL(水平)或者VERTICAL(垂直)

下面是运行结果图:
在这里插入图片描述
在这里插入图片描述
以上分别实现了StaggerdGridLayout的VERTICAL属性(即可以上下拉动数据)与HORIZONTAL属性(即可以左右拉动数据);

注:StaggerdGridLayout 与 GridLayout虽然乍一看看不出什么效果上的区别,这里提示一下,加入把TextView的text变得很长很长,那么这俩种的显示区别就出来了(不同列的数据显示在,一个会参差不齐,一个会水平对齐–直接尝试能够更加直观)

最后,总结一下ListView与RecyclerView的用法区别:
1.使用ListView不用添加依赖,而RecyclerView则需要在app的build.gradle中添加如图所示的依赖文件(因为RecyclerView是第三方的框架):

 implementation 'androidx.recyclerview:recyclerview:1.0.0'

2.ListView的Adapter继承可以选择系统所提供的BaseAdapter以及ArrayAdapter (这俩种Adapter我还没深究区别,目前用起来差不多),自定义的ViewHolder则可以自定义,无需继承任何父类(为了节省动态加载布局以及初始化控件的时间这一性能消耗)
而RecyclerView的adapter以及自定义的ViewHolder则必须要继承自RecyclerView种的adapter以及ViewHolder,并且ViewHolder必须要,为RecyclerView的adapter传递参数的
3.俩者的Adapter重写的方法不同,
4.ListView中最内层的Layout的布局模式只能依靠布局文件去实现,而RecyclerView则需要申请各种LayoutManager去实现各种布局模式,显得较为灵活。
5.监听功能不同,ListView有系统API所提供的setItemOnclickListener():

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.e("MainActivity", "onItemClick: " + "I am " + data.get(position).getName());
            }
        });

而RecyclerView中布局文件的每一个控件都可以单独在Adapter中设置监听,这样显得更加灵活。可以参考上面代码

总结到此结束,希望能帮到刚入坑的萌新们。

最后附上layout布局文件以及菜单的简单使用:
首先是MainActivity:

<?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"
    android:orientation="vertical" >
    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

然后是Main2Activity的:

<?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"
    android:orientation="vertical" >
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</LinearLayout>

最后是item的:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/iv"
        android:layout_width="300dp"
        android:layout_gravity="center"
        android:layout_height="300dp"
        />
    <TextView
        android:id="@+id/tv"
        android:textSize="30dp"
        android:layout_width="match_parent"
        android:layout_gravity="center"
        android:gravity="center"
        android:layout_height="wrap_content"
        />
</LinearLayout>

菜单实现:
1.在res出new 一个Directory文件,命名为menu
2.在menu处new 一个 Menu layout文件
(每一个Menu的item都必须包含title属性,也可以添加group包多个item)

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <item
       android:id="@+id/item1"
       android:title="Go_Next"/>
</menu>

3.在所需要的Activity中重写俩个方法:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.item_for_intent,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.item1:
                Intent intent = new Intent(this, Main2Activity.class);
                startActivity(intent);
                break;
                default:

        }
        return  true;
    }

一个是显示菜单,一个是为菜单的每个项目都设立点击功能,逻辑操作可以自己写,这样就简单的完成了一个菜单了
看一下效果:
在这里插入图片描述
点击一下就能出现相关的菜单选项了。
菜单的更多属性就再自己慢慢探索,这里不细讲

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值