前语

  RecyclerView是Android中非常受欢迎的控件,RecyclerView是官方在Android5.0之后新增加的控件,推出用来代替传统的ListView和GridView列表控件,所以假如你还在运用ListView的话能够替换为RecyclerView了。

正文

  对于RecyclerView的运用依据实践项目进行阐明,一些功用可能是你现在正在做的,对你有协助也说不定。

一、创立项目

  创立一个名为RecyclerViewDemo的Android项目。注意Android Studio的版别运用4.2.1以上或许最新的版别。

Android RecyclerView使用简述

  点击Finish完结项目创立,然后等候项目构建完结,在之前的Android中RecyclerView是需求引进依靠库的,会有v4,v7版别的库,而现在都迁移到androidx下了,目前在项目构建的时分也会主动增加这个material库,里边具有很多的控件,当然也包括RecyclerView。

  下面咱们首要装备一下app下的build.gradle,在android{}闭包里边增加ViewBindingDataBinding的启用,代码如下:

	buildFeatures {
        viewBinding true
        dataBinding true
    }

  装备完之后记住Sync Now点击一下,其他的就没有什么需求装备了,现在就开端运用RecyclerView了,为了便利演示一些,我需求先创立一个基类,在com.llw.recyclerviewdemo包下新建一个BasicActivity,里边的代码如下:

public class BasicActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    protected void back(MaterialToolbar toolbar) {
        toolbar.setNavigationOnClickListener(v -> onBackPressed());
    }
    protected void jumpActivity(final Class<?> clazz) {
        startActivity(new Intent(this, clazz));
    }
	protected void showMsg(CharSequence msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
    /**
     * 获取字符串列表
     */
    protected List<String> getStrings() {
        List<String> lists = new ArrayList<>();
        int num = (int) (1 + Math.random() * (50 - 10 + 1));
        for (int i = 0; i < num; i++) {
            lists.add("第 " + i + " 条数据");
        }
        return lists;
    }
    protected List<BasicBean> getBasicBeans() {
        List<BasicBean> lists = new ArrayList<>();
        int num = (int) (1 + Math.random() * (50 - 10 + 1));
        for (int i = 0; i < num; i++) {
            lists.add(new BasicBean("第 " + i + " 条标题","第 " + i + " 条内容"));
        }
        return lists;
    }
}

也没有什么很杂乱的代码,便是为了便利子类的时分,后边你就会明白为什么这么做了,这儿有一个BasicBean类,一个简略的实体类,在com.llw.recyclerviewdemo下新建一个bean包,包下新建BasicBean类,代码如下:

public class BasicBean {
    private String title;
    private String content;
    public BasicBean(String title, String content) {
        this.title = title;
        this.content = content;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
}

那么现在咱们的根本工作就做好了,最终把系统默许的ActionBar去掉,如下图所示改动就好了。

Android RecyclerView使用简述

  下面要做的便是显现一个根本的RecyclerView,由于除了根本运用还有其他的运用办法,咱们现在只要一个MainActivity,能够作为其他运用办法的进口,所以咱们先修正一下activity_main.xml布局代码,如下所示:

<?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">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:title="RecyclerView运用阐明"
        app:titleTextColor="@color/white" />
    <Button
        android:id="@+id/btn_rv_basic_use"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="6dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView根本运用"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

这儿仅仅增加了一个Toolbar和一个按钮,然后修正MainActivity中的代码,如下所示:

public class MainActivity extends BasicActivity {
    private ActivityMainBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        binding.btnRvBasicUse.setOnClickListener(v ->
                jumpActivity(RvBasicUseActivity.class));
    }
}

  在com.llw.recyclerviewdemo下创立一个RvBasicUseActivity,对应的布局activity_rv_basic_use.xml,下面咱们进入RecyclerView根本运用环节。

二、RecyclerView根本运用

首要咱们修正一下activity_rv_basic_use.xml中的代码,如下所示:

<?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=".RvBasicUseActivity">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/ic_back"
        app:title="RecyclerView根本运用"
        app:titleTextColor="@color/white" />
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

  布局内容很简略,便是toolbar 和 RecyclerView,这儿的toolbar中用到一个图标,用于Toolbar点击回来,在drawable文件夹下新建一个ic_back.xml,代码如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:autoMirrored="true"
    android:tint="@color/white"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0l0,0c0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1l0,0C20,11.45 19.55,11 19,11z" />
</vector>

这儿我打算做一个列表,那么需求一个列表item的布局,然后便是经过适配器去烘托item布局的内容。

① item布局和适配器

在layout文件夹下新建一个item_text_rv.xml文件,里边的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="1dp"
    android:foreground="?attr/selectableItemBackground"
    android:background="@color/white"
    android:padding="16dp"
    android:textColor="@color/black" />

很简略,就一个TextView,显现一下文本即可,下面咱们来创立一个适配器,首要在com.llw.recyclerviewdemo包下新建一个adapter包,包下新建一个StringAdapter类,代码如下:

public class StringAdapter extends RecyclerView.Adapter<StringAdapter.ViewHolder> {
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return null;
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    }
    @Override
    public int getItemCount() {
        return 0;
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}

  这应该数据标准的模板了,下面说一下这个适配器是怎样烘托数据的,首要履行的是onCreateViewHolder,意思很明显创立一个视图,这儿需求回来一个ViewHolder,注意到这儿咱们有一个静态内部类ViewHolder ,继承自RecyclerView.ViewHolder,重写里边的ViewHolder结构办法,获取一个Item的视图View,创立完结之后便是绑定视图,履行onBindViewHolder,绑守时就会烘托视图View,最终履行getItemCount,你能够得到有多少个Item视图。每烘托一个item就会履行一轮。

这个适配器还需求完善,首要要有数据,数据怎样来呢?能够经过类结构办法,在StringAdapter中创立一个变量,然后写一个结构办法,代码如下所示:

	private List<String> lists;
    public StringAdapter(List<String> lists) {
        this.lists = lists;
    }

然后咱们修正onCreateViewHolder中的内容,代码如下:

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

  这儿经过LayoutInflater得到item_text_rv的视图View,注意inflate办法传入的三个参数,其间第二个很多人运用的是null,而我这儿用的是parent,假如用null会使你的item视图自适应巨细,哪怕你设置了match_parent也不可,你能够试试看,得到view之后,经过new ViewHolder(view)的办法创立了一个ViewHolder。

下面是获取item布局中的控件,修正一下内部类ViewHolder中的代码,如下所示:

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

这儿的办法就和之前在Activity中有一些类似,经过findViewById找到控件获取实例。然后进入到onBindViewHolder,代码如下:

	@Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.tvText.setText(lists.get(position));
    }

  在这个回调里边烘托视图,这儿经过holder得到里边的tvText,然后设置TextView的文字内容,这儿能够经过position获取当时的视图方位,也便是数据下标,lists.get(position)就得到当时这个下标所需求烘托到视图的详细数据,最终在getItemCount()回调中,回来数据的长度即可,代码如下:

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

那么适配器的烘托就到此为止了,下面怎样让这个适配器收效呢?

② 显现数据

  修正RvBasicUseActivity中的代码,如下所示:

public class RvBasicUseActivity extends BasicActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rv_basic_use);
        initView();
    }
    private void initView() {
        MaterialToolbar toolbar = findViewById(R.id.materialToolbar);
        RecyclerView rvText = findViewById(R.id.rv_text);
        back(toolbar);
        //获取适配器实例
        StringAdapter stringAdapter = new StringAdapter(getStrings());
        //装备适配器
        rvText.setAdapter(stringAdapter);
        //装备布局管理器
        rvText.setLayoutManager(new LinearLayoutManager(this));
    }
}

  这儿运用了最原始的办法,在onCreate()履行时会调用initView(),initView()办法中,采用findViewById获取toolbar和RecyclerView的实例,然后设置回来工作,之后便是new StringAdapter(getStrings())的办法得到一个stringAdapter ,再设置到RecyclerView中,最终设置布局管理器,这决议你的RecyclerView的内容是怎么翻滚的,默许是纵向的,也便是上下滑动,运转一下。

Android RecyclerView使用简述

OK,显现数据没有问题。

③ 增加Item点击工作

  现在咱们得到了数据,那么怎样经过点击item,显现该条item的数据呢?首要咱们界说一个接口,在com.llw.recyclerviewdemo包下新建一个OnItemClickListener接口,代码如下:

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

下面回到StringAdapter中,增加如下代码:

	private OnItemClickListener listener;
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

然后修正onCreateViewHolder()办法中的内容,代码如下:

	@NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text_rv, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        view.setOnClickListener(v -> {
            if(listener != null){
                listener.onItemClick(v, viewHolder.getAdapterPosition());
            }
        });
        return viewHolder;
    }

  便是给view增加点击工作,然后经过viewHolder得到当时方位,设置回调接口。下面咱们在RvBasicUseActivity中运用点击工作,而完结监听有两种办法,先看第一种:

public class RvBasicUseActivity extends BasicActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rv_basic_use);
        initView();
    }
    private void initView() {
        MaterialToolbar toolbar = findViewById(R.id.materialToolbar);
        RecyclerView rvText = findViewById(R.id.rv_text);
        back(toolbar);
        List<String> strings = getStrings();
        //获取适配器实例
        StringAdapter stringAdapter = new StringAdapter(strings);
        stringAdapter.setOnItemClickListener((view, position) -> showMsg(strings.get(position)));
        //装备适配器
        rvText.setAdapter(stringAdapter);
        //装备布局管理器
        rvText.setLayoutManager(new LinearLayoutManager(this));
    }
}

这种办法便是直接经过匿名接口形式运用,中心便是

		stringAdapter.setOnItemClickListener((view, position) -> showMsg(strings.get(position)));

这是经过Lambda简化之后的,原始的是这样。

		stringAdapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                showMsg(strings.get(position));
            }
        });

第二种办法如下所示:

public class RvBasicUseActivity extends BasicActivity implements OnItemClickListener {
    private List<String> strings;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rv_basic_use);
        initView();
    }
    private void initView() {
        MaterialToolbar toolbar = findViewById(R.id.materialToolbar);
        RecyclerView rvText = findViewById(R.id.rv_text);
        back(toolbar);
        strings = getStrings();
        //获取适配器实例
        StringAdapter stringAdapter = new StringAdapter(strings);
        stringAdapter.setOnItemClickListener(this);
        //装备适配器
        rvText.setAdapter(stringAdapter);
        //装备布局管理器
        rvText.setLayoutManager(new LinearLayoutManager(this));
    }
    @Override
    public void onItemClick(View view, int position) {
        showMsg(strings.get(position));
    }
}

这儿经过具名接口的办法进行完结,能够更直观,这两种办法都行,看个人喜爱,取其一运用即可,这儿我运用的是第一种办法,由于简洁,运转看看作用。

Android RecyclerView使用简述

④ 增加Item子控件点击工作

假如要增加子控件的话,首要要有子控件才行,修正一下item_text_rv.xml,代码如下:

<?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"
    android:layout_marginBottom="1dp"
    android:background="@color/white"
    android:gravity="center_vertical"
    android:foreground="?attr/selectableItemBackground"
    android:orientation="horizontal"
    android:padding="16dp">
    <TextView
        android:id="@+id/tv_text"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:textColor="@color/black" />
    <Button
        android:id="@+id/btn_test"
        android:text="按钮"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

这儿咱们把按钮作为子控件进行点击操作,然后界说一个接口,在listener包下新建一个OnItemChildClickListener接口,代码如下:

public interface OnItemChildClickListener {
    void onItemChildClick(View view, int position);
}

下面回到StringAdapter中,增加代码,如下所示:

	private OnItemChildClickListener childClickListener;
    public void setOnItemChildClickListener(OnItemChildClickListener childClickListener) {
        this.childClickListener = childClickListener;
    }

然后修正onCreateViewHolder办法,增加代码如下:

		//增加子控件点击工作
        view.findViewById(R.id.btn_test).setOnClickListener(v -> {
            if (childClickListener != null) {
                childClickListener.onItemChildClick(v, viewHolder.getAdapterPosition());
            }
        });

增加方位如下图所示:

Android RecyclerView使用简述

好了,回到RvBasicUseActivity中,在initView()办法中增加如下代码:

		//设置适配器Item子控件点击工作
        stringAdapter.setOnItemChildClickListener((view, position) -> showMsg(strings.get(position) + "的按钮"));

增加方位如下图所示:

Android RecyclerView使用简述

便是依葫芦画瓢,下面咱们演示一下。

Android RecyclerView使用简述

⑤ 增加长按工作

  除了工作处理不同,其他都差不多,因而Item长按和Item子控件长按工作我就一起写了,这儿需求创立接口,在listener包下新建一个OnItemLongClickListener 接口,代码如下:

public interface OnItemLongClickListener {
    boolean onItemLongClick(View view, int position);
}

在listener包下新建一个OnItemChildLongClickListener 接口,代码如下:

public interface OnItemChildLongClickListener {
    boolean onItemChildLongClick(View view, int position);
}

下面进入StringAdapter,在onCreateViewHolder中增加如下代码:

		view.setOnLongClickListener(v -> {
            if (longClickListener != null) {
                return longClickListener.onItemLongClick(v, viewHolder.getAdapterPosition());
            }
            return false;
        });
        view.findViewById(R.id.btn_test).setOnLongClickListener(v -> {
            if (childLongClickListener != null) {
                return childLongClickListener.onItemChildLongClick(v, viewHolder.getAdapterPosition());
            }
            return false;
        });

增加方位如下图所示

Android RecyclerView使用简述

  现在onCreateViewHolder中的代码就有一些臃肿了,咱们最好不要这样做,所以咱们需求将方才所增加的工作抽离到一个办法里边,这个办法专门用来处理view的工作,在StringAdapter中新增一个handlerEvents办法,代码如下:

	private void handlerEvents(View view, ViewHolder viewHolder) {
        //增加视图点击工作
        view.setOnClickListener(v -> {
            if (listener != null) {
                listener.onItemClick(v, viewHolder.getAdapterPosition());
            }
        });
        //增加子控件点击工作
        view.findViewById(R.id.btn_test).setOnClickListener(v -> {
            if (childClickListener != null) {
                childClickListener.onItemChildClick(v, viewHolder.getAdapterPosition());
            }
        });
        //增加视图长按工作
        view.setOnLongClickListener(v -> {
            if (longClickListener != null) {
                return longClickListener.onItemLongClick(v, viewHolder.getAdapterPosition());
            }
            return false;
        });
        //增加视图子控件长按工作
        view.findViewById(R.id.btn_test).setOnLongClickListener(v -> {
            if (childLongClickListener != null) {
                return childLongClickListener.onItemChildLongClick(v, viewHolder.getAdapterPosition());
            }
            return false;
        });
    }

然后咱们在onCreateViewHolder()办法中调用handlerEvents()办法即可,修正onCreateViewHolder()办法代码,如下所示:

	 @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text_rv, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        handlerEvents(view, viewHolder);
        return viewHolder;
    }

  你是否注意到长按工作有一个回来值,boolean类型,假如回调消耗了长按,则为 true,不然为 false。怎样了解这句话呢?例如一个控件既有点击又有长按,假如你回来为false,那么再你触发长按之后,回调没有消耗掉,还会再触发点击工作,而设置为true,就不会触发后边的点击工作。

下面回到RvBasicUseActivity中,在initView()办法中增加如下代码:

		//设置适配器Item长按工作
        stringAdapter.setOnItemLongClickListener((view, position) -> {
            showMsg("长按了");
            return true;
        });
        //设置适配器Item子控件长按工作
        stringAdapter.setOnItemChildLongClickListener((view, position) -> {
            showMsg("长按了按钮");
            return true;
        });

至于增加在什么方位,我想不必我再告知你了吧,下面咱们运转一下看看作用。

Android RecyclerView使用简述

⑥ 多个子控件点击工作

  有时分一个Item里边会有多个子控件,每一个都需求有点击工作,这是很常见的工作,那么咱们应该怎样做呢?其实也很简略,首要咱们改动一下item_text_rv.xml,代码如下:

<?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"
    android:layout_marginBottom="1dp"
    android:background="@color/white"
    android:gravity="center_vertical"
    android:foreground="?attr/selectableItemBackground"
    android:orientation="horizontal"
    android:padding="16dp">
    <TextView
        android:id="@+id/tv_text"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:textColor="@color/black" />
    <Button
        android:id="@+id/btn_test"
        android:text="按钮1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/btn_test_2"
        android:layout_marginStart="8dp"
        android:text="按钮2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

这儿我多增加了一个按钮,那么现在就有两个子控件了,回到StringAdapter中,在handlerEvents()办法中,增加如下代码:

		view.findViewById(R.id.btn_test_2).setOnClickListener(v -> {
            if (childClickListener != null) {
                childClickListener.onItemChildClick(v, viewHolder.getAdapterPosition());
            }
        });

然后在RvBasicUseActivity的initView()办法中,修正之前的子控件点击监听中的代码,如下所示:

		stringAdapter.setOnItemChildClickListener((view, position) -> {
            switch (view.getId()) {
                case R.id.btn_test:
                    showMsg(strings.get(position) + "的按钮 1");
                    break;
                case R.id.btn_test_2:
                    showMsg(strings.get(position) + "的按钮 2");
                    break;
            }
        });

尽管都是触发这个回调办法,可是view的id不同,所以咱们能够经过id得知是哪个控件在点击,运转一下:

Android RecyclerView使用简述

这儿实践上咱们写了一段重复的代码,只要控件id不同,因而这段代码还能够优化一下:

		view.findViewById(R.id.btn_test).setOnClickListener(v -> {
            if (childClickListener != null) {
                childClickListener.onItemChildClick(v, viewHolder.getAdapterPosition());
            }
        });
        view.findViewById(R.id.btn_test_2).setOnClickListener(v -> {
            if (childClickListener != null) {
                childClickListener.onItemChildClick(v, viewHolder.getAdapterPosition());
            }
        });

咱们能够在StringAdapter中增加一个addChildClicks()办法,代码如下:

	private void addChildClicks(int[] ids, View view, ViewHolder viewHolder) {
        for (int id : ids) {
            view.findViewById(id).setOnClickListener(v -> {
                if (childClickListener != null) {
                    childClickListener.onItemChildClick(v, viewHolder.getAdapterPosition());
                }
            });
        }
    }

然后在handlerEvents()办法中增加如下代码:

		//增加多个子控件点击工作
        addChildClicks(new int[]{R.id.btn_test, R.id.btn_test_2}, view, viewHolder);

增加方位如下图所示:

Android RecyclerView使用简述

现在运转起来,作用和之前相同,这样做是为了消除重复代码,关于多个子控件的长按工作,也是类似的处理办法,你能够自己试试哦。

三、RecyclerView + ViewBinding运用

  ViewBinding的作用是什么相比就不必我介绍了,简略粗暴一句话,不必手动写findViewById。在com.llw.recyclerviewdemo包下创立一个RvViewBindingActivity,对应的布局是activity_rv_view_binding.xml。然后在主页面增加一个按钮作为进入RvViewBindingActivity的进口, 修正activity_main.xml的代码,增加一个按钮,如下所示:

	<Button
        android:id="@+id/btn_rv_view_binding"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView + ViewBinding"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_rv_basic_use" />

然后回到MainActivity中,在onCreate()办法中,新增如下代码:

	binding.btnRvViewBinding.setOnClickListener(v -> jumpActivity(RvViewBindingActivity.class));

下面咱们修正一下activity_rv_view_binding.xml,代码如下:

<?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=".RvViewBindingActivity">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/ic_back"
        app:title="RecyclerView + ViewBinding"
        app:titleTextColor="@color/white" />
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

很简略,便是一个列表,然后咱们写适配器。

① 适配器

  对于是否运用ViewBinding来说,适配器是要害,布局能够和普通的运用同一个,因而这儿需求从头写一个适配器,在adapter包下新增一个StringViewBindingAdapter类,代码如下:

public class StringViewBindingAdapter extends RecyclerView.Adapter<StringViewBindingAdapter.ViewHolder> {
    private final List<String> lists;
    public StringViewBindingAdapter(List<String> lists) {
        this.lists = lists;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemTextRvBinding binding = ItemTextRvBinding.inflate(LayoutInflater.from(parent.getContext()),parent, false);
        return new ViewHolder(binding);
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.binding.tvText.setText(lists.get(position));
    }
    @Override
    public int getItemCount() {
        return lists.size();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ItemTextRvBinding binding;
        public ViewHolder(@NonNull ItemTextRvBinding itemTextRvBinding) {
            super(itemTextRvBinding.getRoot());
            binding = itemTextRvBinding;
        }
    }
}

  这儿能够看到大部分内容和普通的适配器共同,不同的地便利是视图的生成办法,你能够简略对比一下就明白了,ViewBinding的运用仍是比较简略的,下面咱们相同需求显现出来。

② 显现数据

修正一下RvViewBindingActivity中的代码:

public class RvViewBindingActivity extends BasicActivity {
    private ActivityRvViewBindingBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityRvViewBindingBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        //获取适配器实例
        StringViewBindingAdapter stringAdapter = new StringViewBindingAdapter(getStrings());
        //装备适配器
        binding.rvText.setAdapter(stringAdapter);
        //装备布局管理器
        binding.rvText.setLayoutManager(new LinearLayoutManager(this));
    }
}

Android RecyclerView使用简述

那么后边增加视图的点击工作和子控件的处理,我这儿就一步到位了,一次性写好。

③ 增加控件点击和长按

修正一下StringViewBindingAdapter的代码如下所示:

public class StringViewBindingAdapter extends RecyclerView.Adapter<StringViewBindingAdapter.ViewHolder> {
    private final List<String> lists;
    private OnItemClickListener listener;//视图点击
    private OnItemChildClickListener childClickListener;//视图子控件点击
    private OnItemLongClickListener longClickListener;//视图长按
    private OnItemChildLongClickListener childLongClickListener;//视图子控件长按
    public void setOnItemLongClickListener(OnItemLongClickListener longClickListener) {
        this.longClickListener = longClickListener;
    }
    public void setOnItemChildLongClickListener(OnItemChildLongClickListener childLongClickListener) {
        this.childLongClickListener = childLongClickListener;
    }
    public void setOnItemChildClickListener(OnItemChildClickListener childClickListener) {
        this.childClickListener = childClickListener;
    }
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }
    public StringViewBindingAdapter(List<String> lists) {
        this.lists = lists;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemTextRvBinding binding = ItemTextRvBinding.inflate(LayoutInflater.from(parent.getContext()),parent, false);
        ViewHolder viewHolder = new ViewHolder(binding);
        handlerEvents(binding.getRoot(), viewHolder);
        return viewHolder;
    }
    /**
     * 处理工作
     */
    private void handlerEvents(View view, ViewHolder viewHolder) {
        //增加视图点击工作
        view.setOnClickListener(v -> {
            if (listener != null) {
                listener.onItemClick(v, viewHolder.getAdapterPosition());
            }
        });
        //增加多个子控件点击工作
        addChildClicks(new int[]{R.id.btn_test, R.id.btn_test_2}, view, viewHolder);
        //增加视图长按工作
        view.setOnLongClickListener(v -> {
            if (longClickListener != null) {
                return longClickListener.onItemLongClick(v, viewHolder.getAdapterPosition());
            }
            return false;
        });
        //增加视图子控件长按工作
        view.findViewById(R.id.btn_test).setOnLongClickListener(v -> {
            if (childLongClickListener != null) {
                return childLongClickListener.onItemChildLongClick(v, viewHolder.getAdapterPosition());
            }
            return false;
        });
    }
    /**
     * 增加子控件点击工作
     * @param ids 控件id数组
     */
    private void addChildClicks(int[] ids, View view, ViewHolder viewHolder) {
        for (int id : ids) {
            view.findViewById(id).setOnClickListener(v -> {
                if (childClickListener != null) {
                    childClickListener.onItemChildClick(v, viewHolder.getAdapterPosition());
                }
            });
        }
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.binding.tvText.setText(lists.get(position));
    }
    @Override
    public int getItemCount() {
        return lists.size();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ItemTextRvBinding binding;
        public ViewHolder(@NonNull ItemTextRvBinding itemTextRvBinding) {
            super(itemTextRvBinding.getRoot());
            binding = itemTextRvBinding;
        }
    }
}

修正一下RvViewBindingActivity中的代码,如下所示:

public class RvViewBindingActivity extends BasicActivity {
    private ActivityRvViewBindingBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityRvViewBindingBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        List<String> strings = getStrings();
        //获取适配器实例
        StringViewBindingAdapter stringAdapter = new StringViewBindingAdapter(strings);
        //设置适配器Item点击工作
        stringAdapter.setOnItemClickListener((view, position) -> showMsg(strings.get(position)));
        //设置适配器Item子控件点击工作
        stringAdapter.setOnItemChildClickListener((view, position) -> {
            switch (view.getId()) {
                case R.id.btn_test:
                    showMsg(strings.get(position) + "的按钮 1");
                    break;
                case R.id.btn_test_2:
                    showMsg(strings.get(position) + "的按钮 2");
                    break;
            }
        });
        //设置适配器Item长按工作
        stringAdapter.setOnItemLongClickListener((view, position) -> {
            showMsg("长按了");
            return true;
        });
        //设置适配器Item子控件长按工作
        stringAdapter.setOnItemChildLongClickListener((view, position) -> {
            showMsg("长按了按钮");
            return true;
        });
        //装备适配器
        binding.rvText.setAdapter(stringAdapter);
        //装备布局管理器
        binding.rvText.setLayoutManager(new LinearLayoutManager(this));
    }
}

  你会发现适配器和活动的代码与根本运用大致相同,仅有的差异便是视图生成办法不同,这个运转作用和根本运用的就完全共同了。

四、RecyclerView + DataBinding运用

  ViewBinding对你来说或许太简略了,那么下面咱们学习在RecyclerView中运用DataBinding,这个就没有那么简略了,当然这是相对于ViewBinding来说的。ViewBinding假如是视图的话,那么DataBinding便是在ViewBinding的基础上加上了数据烘托,下面咱们来看看。

  首要仍是那个问题,咱们需求创立一个进口,在com.llw.recyclerviewdemo包下创立一个RvDataBindingActivity,对应的布局是activity_rv_data_binding.xml。然后修正activity_main.xml,在里边增加一个按钮,代码如下:

	<Button
        android:id="@+id/btn_rv_data_binding"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView + DataBinding"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_rv_view_binding" />

然后修正MainActivity中onCreate()办法中增加代码,如下所示:

	binding.btnRvDataBinding.setOnClickListener(v -> jumpActivity(RvDataBindingActivity.class));

① Activity运用DataBinding

  假如你的Activity对应的xml中的某一个控件需求运用DataBinding,那么你的Activity也需求运用DataBinding,Activity对应的xml中也需求运用DataBinding,首要咱们来修正一下activity_rv_data_binding中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".RvDataBindingActivity">
        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/materialToolbar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            android:theme="?attr/actionBarTheme"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:navigationIcon="@drawable/ic_back"
            app:title="RecyclerView + DataBinding"
            app:titleTextColor="@color/white" />
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_text"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

注意看,最外层是layout,然后才是咱们的ConstraintLayout,这是DataBinding需求这么做的,下面咱们回到RvDataBindingActivity中,修正代码如下所示:

public class RvDataBindingActivity extends BasicActivity {
    private ActivityRvDataBindingBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this,R.layout.activity_rv_data_binding);
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
    }
}

这儿的写法就和ViewBinding不同了,注意这一行代码:

DataBindingUtil.setContentView(this,R.layout.activity_rv_data_binding);

现在你能够先运转一下,看看是否能在主页面经过按钮正常进入RvDataBindingActivity页面,能够的话再往下继续进行。

② item布局

这个类仍是比较简略的,下面咱们创立一个适配布局,在layout下新建一个item_text_data_rv.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="basicBean"
            type="com.llw.recyclerviewdemo.bean.BasicBean" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="1dp"
        android:foreground="?attr/selectableItemBackground"
        android:background="@color/white"
        android:orientation="vertical"
        android:padding="16dp">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{basicBean.title}"
            android:textColor="@color/black" />
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{basicBean.content}"
            android:textColor="@color/black" />
    </LinearLayout>
</layout>

  这儿看到引进了方才写的实体Bean,variable表明可变数据,< data >标签中的除了variable还有import,import用于引进数据,然后咱们在看下面的布局的TextView中,android:text=”@{basicBean.title}”,这儿写法有点像Kotlin,set和get办法都是title。这个写法的意思便是setText(basicBean.getTitle());假如你之前没有用过DataBinding的话,那么这对你来说会充满新鲜感,当然了修正文本是最简略的运用了。

③ 适配器

在adapter下新建一个StringDataBindingAdapter类,代码如下:

public class StringDataBindingAdapter extends RecyclerView.Adapter<StringDataBindingAdapter.ViewHolder> {
    private final List<BasicBean> lists;
    public StringDataBindingAdapter(List<BasicBean> lists) {
        this.lists = lists;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemTextDataRvBinding binding = ItemTextDataRvBinding.inflate(LayoutInflater.from(parent.getContext()),parent, false);
        return new ViewHolder(binding);
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        ItemTextDataRvBinding binding = DataBindingUtil.getBinding(holder.binding.getRoot());
        if (binding != null) {
            binding.setBasicBean(lists.get(position));
            binding.executePendingBindings();
        }
    }
    @Override
    public int getItemCount() {
        return lists.size();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ItemTextDataRvBinding binding;
        public ViewHolder(@NonNull ItemTextDataRvBinding itemTextDataRvBinding) {
            super(itemTextDataRvBinding.getRoot());
            binding = itemTextDataRvBinding;
        }
    }
}

  这儿大部分内容和StringViewBindingAdapter的初始版相同,下面咱们来看不相同的地方,也便是这个数据的烘托不同,代码如下:

	@Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        ItemTextDataRvBinding binding = DataBindingUtil.getBinding(holder.binding.getRoot());
        if (binding != null) {
            binding.setBasicBean(lists.get(position));
            binding.executePendingBindings();
        }
    }

  DataBindingUtil是DataBinding中很重要的一个类,在RvDataBindingActivity中也用到了,经过这个办法能够得到ItemTextDataRvBinding 的实例,然后设置数据源,你可能会很古怪binding.setBasicBean的代码哪里来的,便是你的variable增加时就会经过编译时技能生成的,按住Ctrl键点击setBasicBean就会进入到xml中variable标签的方位,这儿的name是basicBean,假如你改成basicBean2,那么你的setBasicBean就会报红,需求改成setBasicBean2,能够试试看哦。当然了basicBean改了,那么text=“”的内容也要改,所以这个name很重要。然后咱们再来看executePendingBindings()办法,方才咱们经过setBasicBean设置了可变数据,那么要使这个设置收效就需求executePendingBindings()函数,必定不要漏掉了。

下面便是显现数据了,这儿反而很简略,只需求修正一下RvDataBindingActivity中的initView()中的代码即可,代码如下:

	private void initView() {
        back(binding.materialToolbar);
        //获取适配器实例
        StringDataBindingAdapter stringAdapter = new StringDataBindingAdapter(getBasicBeans());
        //装备适配器
        binding.rvText.setAdapter(stringAdapter);
        //装备布局管理器
        binding.rvText.setLayoutManager(new LinearLayoutManager(this));
    }

咱们运转看看作用

Android RecyclerView使用简述

增加Item的点击工作,你能够和ViewBinding的运用相同。

④ 增加item点击和长按工作

这儿修正StringDataBindingAdapter的代码,如下所示:

public class StringDataBindingAdapter extends RecyclerView.Adapter<StringDataBindingAdapter.ViewHolder> {
    private final List<BasicBean> lists;
    private OnItemClickListener listener;//视图点击
    private OnItemLongClickListener longClickListener;//视图长按
    public void setOnItemLongClickListener(OnItemLongClickListener longClickListener) {
        this.longClickListener = longClickListener;
    }
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }
    public StringDataBindingAdapter(List<BasicBean> lists) {
        this.lists = lists;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemTextDataRvBinding binding = ItemTextDataRvBinding.inflate(LayoutInflater.from(parent.getContext()),parent, false);
        ViewHolder viewHolder = new ViewHolder(binding);
        handlerEvents(binding.getRoot(), viewHolder);
        return viewHolder;
    }
    /**
     * 处理工作
     */
    private void handlerEvents(View view, ViewHolder viewHolder) {
        //增加视图点击工作
        view.setOnClickListener(v -> {
            if (listener != null) {
                listener.onItemClick(v, viewHolder.getAdapterPosition());
            }
        });
        //增加视图长按工作
        view.setOnLongClickListener(v -> {
            if (longClickListener != null) {
                return longClickListener.onItemLongClick(v, viewHolder.getAdapterPosition());
            }
            return false;
        });
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        ItemTextDataRvBinding binding = DataBindingUtil.getBinding(holder.binding.getRoot());
        if (binding != null) {
            binding.setBasicBean(lists.get(position));
            binding.executePendingBindings();
        }
    }
    @Override
    public int getItemCount() {
        return lists.size();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ItemTextDataRvBinding binding;
        public ViewHolder(@NonNull ItemTextDataRvBinding itemTextDataRvBinding) {
            super(itemTextDataRvBinding.getRoot());
            binding = itemTextDataRvBinding;
        }
    }
}

然后修正RvDataBindingActivity的代码,如下所示:

public class RvDataBindingActivity extends BasicActivity {
    private ActivityRvDataBindingBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_rv_data_binding);
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        List<BasicBean> basicBeans = getBasicBeans();
        //获取适配器实例
        StringDataBindingAdapter stringAdapter = new StringDataBindingAdapter(basicBeans);
        stringAdapter.setOnItemClickListener((view, position) -> {
            showMsg("点击了" + basicBeans.get(position).getTitle());
        });
        stringAdapter.setOnItemLongClickListener((view, position) -> {
            showMsg("长按了" + basicBeans.get(position).getTitle());
            return true;
        });
        //装备适配器
        binding.rvText.setAdapter(stringAdapter);
        //装备布局管理器
        binding.rvText.setLayoutManager(new LinearLayoutManager(this));
    }
}

看看运转作用

Android RecyclerView使用简述

关于适配器中的点击工作的处理还有很多DataBinding的写法,这儿就不逐个阐明晰,下面进入进阶运用。

五、RecyclerView下拉改写和上拉加载

  在日常运用中,RecyclerView的数据并不是一次性都加载出来的,会有分页,从头加载等操作,而手机上操作便是下拉改写和上拉加载。

① 增加依靠库

下拉改写的动作能够由一个库来完结,在app的build.gradle中dependencies{}闭包中增加如下依靠:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

然后Sync Now,然后在activity_main.xml中增加一个按钮,作为进入此功用的进口,代码如下:

	<Button
        android:id="@+id/btn_rv_refresh_load"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView 下拉改写 + 上拉加载"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_rv_data_binding" />

下面在MainActivity中onCreate()办法中增加如下代码:

binding.btnRvRefreshLoad.setOnClickListener(v -> jumpActivity(RvRefreshLoadActivity.class));

这儿咱们还没有这个RvRefreshLoadActivity的,创立它,对应的布局为activity_rv_refresh_load.xml,里边的代码如下所示:

<?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=".RvRefreshLoadActivity">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/ic_back"
        app:title="RecyclerView 下拉改写 + 上拉加载"
        app:titleTextColor="@color/white" />
    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

  这儿的代码也很简略,经过一个SwipeRefreshLayout包裹住RecyclerView,这个控件能够感知下拉的动作,下面咱们来完结下拉改写。

② 下拉改写数据

进入RvRefreshLoadActivity中,修正代码如下:

public class RvRefreshLoadActivity extends BasicActivity {
    private ActivityRvRefreshLoadBinding binding;
    private final List<String> strings = new ArrayList<>();
    private int lastVisibleItem;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityRvRefreshLoadBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        strings.addAll(getStrings());
        //获取适配器实例
        BasicAdapter stringAdapter = new BasicAdapter(strings);
        final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //装备布局管理器
        binding.rvText.setLayoutManager(linearLayoutManager);
        //装备适配器
        binding.rvText.setAdapter(stringAdapter);    }
}

  这部分的代码相比你现已很熟悉了,由于前面现已呈现过很屡次,下面咱们增加下拉动作的监听,就在这个装备适配器代码的下面增加就能够了,代码如下:

		binding.refresh.setOnRefreshListener(() -> {
            strings.clear();
            strings.addAll(getStrings());
            new Handler().postDelayed(() -> {
                stringAdapter.notifyDataSetChanged();
                binding.refresh.setRefreshing(false);
            }, 1000);
        });

  这儿边的代码很简略,改写之前先铲除列表的一切数据,然后增加新数据,增加了一个延时烘托数据的动作,烘托数据之后关闭改写动作。咱们来看看作用图:

Android RecyclerView使用简述

③ 上拉加载更多

在下拉改写的代码下面增加上拉加载更多的代码,如下所示:

	binding.rvText.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 == stringAdapter.getItemCount()) {
                    if (stringAdapter.getItemCount() > 50) {
                        showMsg("已加载悉数");
                    } else {
                        showMsg("加载更多");
                        new Handler().postDelayed(() -> {
                            strings.addAll(getStrings());
                            stringAdapter.notifyDataSetChanged();
                        }, 1000);
                    }
                }
            }
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                //获取最终一个可见Item的下标
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
            }
        });

  这一段代码就比较多了,阐明一下,先看onScrolled回调办法,这是表明RecyclerView在翻滚的回调,在onScrolled()办法中,咱们经过linearLayoutManager能够得到最终一个可见Item的下标,然后回到onScrollStateChanged()回调办法中,这个办法表明滑动状况改变,这儿判别RecyclerView是否处于闲暇中,一起判别lastVisibleItem + 1 是否等于列表适配器中的Item个数,为什么要+1?由于下标是从0开端的,这个判别的含义便是知道当时列表是否滑动到底部了,是的话咱们再处理是否需求加载更多数据,这儿我增加了一个条件,假如当时i适配器的item个数大于50则表明现已加载了悉数,不然再增加新数据进去,经过解说相信你能了解为什么这么做了,下面咱们运转一下看看作用。

Android RecyclerView使用简述

六、RecyclerView多布局运用

  在前面的运用中咱们在操作写适配器的代码时,都是一个item布局,而有时分数据不同需求显现的布局也不同,就存在多布局的情况,这种情况应该怎样处理呢?其实也不难,下面咱们来学习一下。

首要在com.llw.recyclerviewdemo创立一个RvMultipleLayoutsActivity,对应的布局是activity_rv_multiple_layouts.xml,里边的代码如下:

<?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=".RvMultipleLayoutsActivity">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/ic_back"
        app:title="RecyclerView 多布局运用"
        app:titleTextColor="@color/white" />
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

下面咱们相同在activity_main.xml中增加一个按钮,代码如下:

<Button
        android:id="@+id/btn_rv_multiple_layouts"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView 多布局运用"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_rv_refresh_load" />

然后在MainActivity中的onCreate()办法中跳转到RvMultipleLayoutsActivity中,增加代码如下:

binding.btnRvMultipleLayouts.setOnClickListener(v -> jumpActivity(RvMultipleLayoutsActivity.class));

根本的预备工作就做好了,下面咱们首要创立布局,例如音讯列表,分别人和我自己布局办法。

① 创立布局Item

在layout下新建一个item_other_rv.xml,里边的代码如下:

<?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="wrap_content">
    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:background="@drawable/ic_launcher_background"
        app:srcCompat="@drawable/ic_launcher_foreground" />
    <TextView
        android:id="@+id/tv_content"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:textColor="@color/black"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="@+id/imageView2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView2"
        app:layout_constraintTop_toTopOf="@+id/imageView2" />
</androidx.constraintlayout.widget.ConstraintLayout>

这是别人的音讯布局,下面创立自己的音讯布局,相同在layout下创立item_myself_rv.xml,代码如下:

<?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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:background="@drawable/ic_launcher_background"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/ic_launcher_foreground" />
    <TextView
        android:id="@+id/tv_content"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:gravity="end"
        android:text="TextView"
        android:textColor="@color/black"
        app:layout_constraintBottom_toBottomOf="@+id/imageView2"
        app:layout_constraintEnd_toStartOf="@+id/imageView2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/imageView2" />
</androidx.constraintlayout.widget.ConstraintLayout>

  这个布局由于音讯是在右边,所以我对TextView的android:gravity属性做了调整,让里边的文字居右显现,现在布局就创立好了,下面咱们需求一个数据Bean。

② 创立数据Bean

在bean包下新建一个Message类,里边的代码如下:

public class Message {
    private int type;
    private String content;
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public Message(int type, String content) {
        this.type = type;
        this.content = content;
    }
}

  这个数据Bean仍是很简略的,便是用来区别音讯的类型,还有音讯的内容,仅仅模拟一下罢了,相同咱们需求供给一些假音讯数据,能够直接在BasicActivity中增加,增加一个办法,代码如下:

	protected List<Message> getMessages() {
        List<Message> messages = new ArrayList<>();
        int num = (int) (1 + Math.random() * (20 - 10 + 1));
        for (int i = 0; i < num; i++) {
            int type = i % 2 == 0 ? 0 : 1;
            String content = type == 0 ? "今日你搞钱了吗?" : "摸鱼的时分就专心摸鱼!";
            messages.add(new Message(type, content));
        }
        return messages;
    }

这儿的代码仍是比较简略的,便是区别一下别人和自己,显现不同的类型和内容,下面就到了咱们的重头戏,适配器了。

③ 适配器

先说一下适配器中要做什么,适配中要区别View类型,要构建不同的ViewHolder,在adapter包下新建一个MessageAdapter,里边的代码如下:

public class MessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private final List<Message> messages;
    private static final int OTHER = 0;
    private static final int MYSELF = 1;
    public MessageAdapter(List<Message> messages) {
        this.messages = messages;
    }
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder;
        if (viewType == OTHER) {
            viewHolder = new OtherViewHolder(ItemOtherRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
        } else {
            viewHolder = new MyselfViewHolder(ItemMyselfRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
        }
        return viewHolder;
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof OtherViewHolder) {
            ((OtherViewHolder) holder).otherBinding.tvContent.setText(messages.get(position).getContent());
        } else if (holder instanceof MyselfViewHolder) {
            ((MyselfViewHolder) holder).myselfBinding.tvContent.setText(messages.get(position).getContent());
        }
    }
    @Override
    public int getItemCount() {
        return messages.size();
    }
    @Override
    public int getItemViewType(int position) {
        if (messages.get(position).getType() == 0) {
            return OTHER;
        } else {
            return MYSELF;
        }
    }
    public static class OtherViewHolder extends RecyclerView.ViewHolder {
        public ItemOtherRvBinding otherBinding;
        public OtherViewHolder(@NonNull ItemOtherRvBinding itemOtherRvBinding) {
            super(itemOtherRvBinding.getRoot());
            otherBinding = itemOtherRvBinding;
        }
    }
    public static class MyselfViewHolder extends RecyclerView.ViewHolder {
        public ItemMyselfRvBinding myselfBinding;
        public MyselfViewHolder(@NonNull ItemMyselfRvBinding itemMyselfRvBinding) {
            super(itemMyselfRvBinding.getRoot());
            myselfBinding = itemMyselfRvBinding;
        }
    }
}

  这是完整的代码,下面我来阐明一下,首要咱们看到有两个内部类,OtherViewHolderMyselfViewHolder ,用于对应两个不同的item布局,这个里边的代码没啥说的,然后当时的MessageAdapter继承了RecyclerView.Adapter<RecyclerView.ViewHolder>,这儿是RecyclerView.ViewHolder而不是咱们自己创立的我界说OtherViewHolderMyselfViewHolder ,这是由于咱们需求在onCreateViewHolder中去依据ViewType不同创立不同的ViewHolder。要害代码如下所示:

	@NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder;
        if (viewType == OTHER) {
            viewHolder = new OtherViewHolder(ItemOtherRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
        } else {
            viewHolder = new MyselfViewHolder(ItemMyselfRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
        }
        return viewHolder;
    }

  下面来看ViewType的判别了OTHERMYSELF两个常量作为类型判别,在getItemViewType()回调办法中进行处理,然后回来不同的ViewType,之前咱们一直没有用到过这个办法,由于item是单一的,现在不是了,所假如你的item无论是多少个类型,都能够这么去做。要害代码如下所示:

	@Override
    public int getItemViewType(int position) {
        if (messages.get(position).getType() == 0) {
            return OTHER;
        } else {
            return MYSELF;
        }
    }

  现在ViewTypeViewHolder都知道了,下面便是数据烘托的处理了,也很简略。由于在前面创立ViewHolder时用了不同的内部类,那么在数据烘托的时分也能够经过这个来判别,当时烘托的是哪一个ViewHolder中的视图,要害代码如下所示:

	@Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof OtherViewHolder) {
            ((OtherViewHolder) holder).otherBinding.tvContent.setText(messages.get(position).getContent());
        } else if (holder instanceof MyselfViewHolder) {
            ((MyselfViewHolder) holder).myselfBinding.tvContent.setText(messages.get(position).getContent());
        }
    }

其他的一些代码就没有什么好解说的了,下面来显现数据,修正一下RvMultipleLayoutsActivity的代码,如下所示:

public class RvMultipleLayoutsActivity extends BasicActivity {
    private ActivityRvMultipleLayoutsBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityRvMultipleLayoutsBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        binding.rvText.setLayoutManager(new LinearLayoutManager(this));
        binding.rvText.setAdapter(new MessageAdapter(getMessages()));
    }
}

这根本上没什么好阐明,假如你是一路看下来的话,下面咱们运转一下:

Android RecyclerView使用简述

这儿仅仅一个简略的演示多布局的功用,实践上的功用会比这个杂乱,可是逻辑是相同的。

七、RecyclerView多级列表运用

  RecyclerView的item有时分又会包裹一个RecyclerView,类似于QQ的分组,分组是一个列表,分组的item能够打开,打开后是一个列表,里边是显现该分组下的人员的,这个功用咱们就能够经过RecyclerView嵌套RecyclerView的办法完结二级列表,下面来看看应该怎样做。

首要要做的仍是有一个进口,在activity_main.xml中新增一个按钮,代码如下:

	<Button
        android:id="@+id/btn_rv_multilevel_list"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView 多级列表运用"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_rv_multiple_layouts" />

然后在MainActivity的onCreate()办法中增加如下代码:

	binding.btnRvMultilevelList.setOnClickListener(v -> jumpActivity(RvMultilevelListActivity.class));

com.llw.recyclerviewdemo包下创立一个RvMultilevelListActivity,对应的布局是activity_rv_multilevel_list.xml,代码如下:

<?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=".RvMultilevelListActivity">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/ic_back"
        app:title="RecyclerView 多级列表运用"
        app:titleTextColor="@color/white" />
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_group"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

① 创立布局Item

这儿咱们相同有两个item,可是关系上是父子,不是同级的,在layout下创立一个item_group_rv.xml,里边的代码如下所示:

<?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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:id="@+id/group"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/white"
        android:foreground="?attr/selectableItemBackground"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
        <ImageView
            android:id="@+id/iv_flag"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:src="@drawable/ic_right" />
        <TextView
            android:id="@+id/tv_group_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="end"
            android:singleLine="true"
            android:text="分组名"
            android:textColor="@color/black" />
    </LinearLayout>
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_contacts"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:visibility="gone"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/group" />
</androidx.constraintlayout.widget.ConstraintLayout>

  这个item布局里边便是放了RecyclerView,正常情况下这个RecyclerView躲藏,能够经过点击group的布局操控RecyclerView显现或躲藏,里边还用了一个图标来增加显现和躲藏的作用,在drawable下新增ic_right.xml,代码如下:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:autoMirrored="true"
    android:tint="#000000"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M10,17l5,-5 -5,-5v10z" />
</vector>

再增加一个ic_down.xml,代码如下:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:tint="#000000"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M7,10l5,5 5,-5z" />
</vector>

下面咱们在layout下再创立一个item_contacts_rv.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/tv_contacts_name"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:layout_marginBottom="1dp"
    android:background="#F8F8F8"
    android:gravity="center_vertical"
    android:paddingStart="24dp"
    android:text="联系人"
    android:textColor="@color/black"
    tools:ignore="RtlSymmetry" />

这个联系人Item就比较简略了,只要一个TextView。布局item有了,下面便是数据了。

② 创立数据Bean

这个数据Bean,就比较简略了,只要有分组名和联系人名就能够了,在bean包下新建一个Group类,代码如下:

public class Group {
    private String name;
    private List<Contacts> contacts;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Contacts> getContacts() {
        return contacts;
    }
    public void setContacts(List<Contacts> contacts) {
        this.contacts = contacts;
    }
    public Group(String name, List<Contacts> contacts) {
        this.name = name;
        this.contacts = contacts;
    }
    public static class Contacts {
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Contacts(String name) {
            this.name = name;
        }
    }
}

然后相同能够在BasicActivity中增加一个办法,供给分组数据,代码如下:

	protected List<Group> getGroups() {
        List<Group> groups = new ArrayList<>();
        int groupNum = (int) (1 + Math.random() * (20 - 10 + 1));
        for (int i = 0; i < groupNum; i++) {
            List<Group.Contacts> contacts = new ArrayList<>();
            int contactsNum = (int) (1 + Math.random() * (20 - 10 + 1));
            for (int j = 0; j < contactsNum; j++) {
                contacts.add(new Group.Contacts("搞钱" + (j + 1) + "号"));
            }
            groups.add(new Group("搞钱" + (i + 1) + "组", contacts));
        }
        return groups;
    }

这个代码就不必阐明晰吧,下面进入重头戏,适配器。

③ 适配器

  这儿的适配器有两个,一个用来显现分组,一个用来显现联系人,从易到难,先来看联系人的,在adapter包下新建一个ContactsAdapter类,代码如下:

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {
    private final List<Group.Contacts> contacts;
    public ContactsAdapter(List<Group.Contacts> contacts) {
        this.contacts = contacts;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(ItemContactsRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.binding.tvContactsName.setText(contacts.get(position).getName());
    }
    @Override
    public int getItemCount() {
        return contacts.size();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        ItemContactsRvBinding binding;
        public ViewHolder(@NonNull ItemContactsRvBinding itemContactsRvBinding) {
            super(itemContactsRvBinding.getRoot());
            binding = itemContactsRvBinding;
        }
    }
}

这儿边就没什么好说,你都见过很屡次了,下面侧重来看分组适配器,在adapter包下新建一个GroupAdapter类,里边的代码如下:

public class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.ViewHolder> {
    private final List<Group> groups;
    public GroupAdapter(List<Group> groups) {
        this.groups = groups;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ViewHolder viewHolder = new ViewHolder(ItemGroupRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
        viewHolder.binding.group.setOnClickListener(v -> {
            //是否显现
            boolean isShow = viewHolder.binding.rvContacts.getVisibility() == View.VISIBLE;
            //修正图标
            viewHolder.binding.ivFlag.setImageDrawable(isShow ?
                    ContextCompat.getDrawable(parent.getContext(), R.drawable.ic_right) : ContextCompat.getDrawable(parent.getContext(), R.drawable.ic_down));
            //显现或躲藏联系人列表
            viewHolder.binding.rvContacts.setVisibility(isShow ? View.GONE : View.VISIBLE);
        });
        return viewHolder;
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Group group = groups.get(position);
        holder.binding.tvGroupName.setText(group.getName());
        holder.binding.rvContacts.setAdapter(new ContactsAdapter(group.getContacts()));
        holder.binding.rvContacts.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext()));
    }
    @Override
    public int getItemCount() {
        return groups.size();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ItemGroupRvBinding binding;
        public ViewHolder(@NonNull ItemGroupRvBinding itemGroupRvBinding) {
            super(itemGroupRvBinding.getRoot());
            binding = itemGroupRvBinding;
        }
    }
}

这个分组适配器的代码就侧重阐明一下,怎样操控联系人列表显现或躲藏,在onCreateViewHolder()办法中,增加了一个点击工作,中心代码如下:

		viewHolder.binding.group.setOnClickListener(v -> {
            //是否显现
            boolean isShow = viewHolder.binding.rvContacts.getVisibility() == View.VISIBLE;
            //修正图标
            viewHolder.binding.ivFlag.setImageDrawable(isShow ?
                    ContextCompat.getDrawable(parent.getContext(), R.drawable.ic_right) : ContextCompat.getDrawable(parent.getContext(), R.drawable.ic_down));
            //显现或躲藏联系人列表
            viewHolder.binding.rvContacts.setVisibility(isShow ? View.GONE : View.VISIBLE);
        });

  在创立分组item布局的时分我设置RecyclerView为躲藏的,在点击group所在的LinearLayout布局时,对RecyclerView是否躲藏做判别,首要是修正图标,然后是修正RecyclerView是显现仍是躲藏,也是比较简略的代码,可是有用,这儿的点击工作处理在适配器中处理会更简略,所以就直接处理了。下面便是在分组适配器加载联系人列表数据了,中心代码如下所示:

	@Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Group group = groups.get(position);
        holder.binding.tvGroupName.setText(group.getName());
        holder.binding.rvContacts.setAdapter(new ContactsAdapter(group.getContacts()));
        holder.binding.rvContacts.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext()));
    }

这个代码是否似曾类似呢?便是这么简略,不要把工作想杂乱了,适配器中其他的就没有什么好说的了,下面咱们修正一下RvMultilevelListActivity的代码,如下所示:

public class RvMultilevelListActivity extends BasicActivity {
    private ActivityRvMultilevelListBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityRvMultilevelListBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        binding.rvGroup.setAdapter(new GroupAdapter(getGroups()));
        binding.rvGroup.setLayoutManager(new LinearLayoutManager(this));
    }
}

最终咱们运转看看作用。

Android RecyclerView使用简述

  其间这种二级列表还有操作办法,便是当你打开其间一个分组时,其他的分组假如有打开的那么就需求收缩,也便是说同一时间只要一个分组打开,你能够想想要怎样做。

八、RecyclerView动态更改数据

  之前咱们显现数据都是直接显现的,后边在运用进程中并没有对数据进行更改,那么下面咱们来进行更改试试看。首要仍是增加进口,在activity_main.xml中新增一个按钮,代码如下:

	<Button
        android:id="@+id/btn_rv_dynamically_change_data"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView 动态更改数据"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_rv_multilevel_list" />

然后在MainActivity中onCreate()办法中增加如下代码:

	binding.btnRvDynamicallyChangeData.setOnClickListener(v -> jumpActivity(RvDynamicallyChangeActivity.class));

下面在com.llw.recyclerviewdemo包下新建RvDynamicallyChangeActivity,对应布局activity_rv_dynamically_change.xml,布局代码如下:

<?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=".RvDynamicallyChangeActivity">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/ic_back"
        app:title="RecyclerView 动态更改数据"
        app:titleTextColor="@color/white">
        <TextView
            android:id="@+id/tv_edit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end"
            android:gravity="center"
            android:padding="16dp"
            android:text="修正"
            android:textColor="@color/white" />
    </com.google.android.material.appbar.MaterialToolbar>
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_text"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/tv_select_num"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
    <TextView
        android:id="@+id/tv_select_num"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:gravity="center"
        android:visibility="gone"
        android:padding="16dp"
        android:text="选中0个"
        android:textColor="@color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

  根本的都预备好了,下面咱们进行代码的编写,先说一下要做的内容是什么?首要是一个列表,这个列表中的item能够选中,选中或撤销选中,都需求更改选中记载,听起来是不是很简略呢?这儿边涉及到一个Activity和Adapter交互的进程。

① 创立布局item和数据Bean

首要咱们仍是从创立布局item开端,在layout下新建一个item_select_rv.xml,代码如下:

<?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"
    android:id="@+id/item_select"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_marginBottom="1dp"
    android:background="@color/white"
    android:foreground="?attr/selectableItemBackground"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:text="TextView"
        android:textColor="@color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <CheckBox
        android:id="@+id/cb_select"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="false"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

这儿的选中框我是躲藏的,需求在Activity中操控Adapter中的选中框显现或躲藏,下面创立数据Bean,在bean包下新建SelectBean类,代码如下:

public class SelectBean {
    private boolean select;
    private String content;
    public boolean isSelect() {
        return select;
    }
    public void setSelect(boolean select) {
        this.select = select;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public SelectBean(boolean select, String content) {
        this.select = select;
        this.content = content;
    }
}

然后相同在BasicActivity中增加一个办法,供给数据,代码如下:

	protected List<SelectBean> getSelects() {
        List<SelectBean> selectBeans = new ArrayList<>();
        int num = (int) (1 + Math.random() * (50 - 10 + 1));
        for (int i = 0; i < num; i++) {
            selectBeans.add(new SelectBean(false, "第 " + i + " 条数据"));
        }
        return selectBeans;
    }

下面咱们先显现数据,然后由Activity去操控Adapter中item布局变化。

② 适配器和显现数据

在adapter包下新建一个SelectAdapter类,里边的代码如下所示:

public class SelectAdapter extends RecyclerView.Adapter<SelectAdapter.ViewHolder> {
    private final List<SelectBean> selectBeans;
    private boolean show;
    public boolean isShow() {
        return show;
    }
    @SuppressLint("NotifyDataSetChanged")
    public void setShow(boolean show) {
        this.show = show;
        notifyDataSetChanged();
    }
    public SelectAdapter(List<SelectBean> selectBeans) {
        this.selectBeans = selectBeans;
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(ItemSelectRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        SelectBean selectBean = selectBeans.get(position);
        holder.binding.tvContent.setText(selectBean.getContent());
        holder.binding.cbSelect.setChecked(selectBean.isSelect());
        holder.binding.cbSelect.setVisibility(isShow() ? View.VISIBLE : View.GONE);
    }
    @Override
    public int getItemCount() {
        return selectBeans.size();
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ItemSelectRvBinding binding;
        public ViewHolder(@NonNull ItemSelectRvBinding itemSelectRvBinding) {
            super(itemSelectRvBinding.getRoot());
            binding = itemSelectRvBinding;
        }
    }
}

  注意看这个适配器中,我增加了一个show变量,用来操控适配器Item的选中框是否显现,供给了show变量的get和set办法,在set办法中赋值之后调用notifyDataSetChanged()办法对适配器进行改写,这个办法会触发onBindViewHolder(),在这个办法中能够看到依据show的状况显现仍是躲藏选中框。

下面咱们修正RvDynamicallyChangeActivity,代码如下:

public class RvDynamicallyChangeActivity extends BasicActivity {
    private ActivityRvDynamicallyChangeBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityRvDynamicallyChangeBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        SelectAdapter selectAdapter = new SelectAdapter(getSelects());
        binding.rvText.setLayoutManager(new LinearLayoutManager(this));
        binding.rvText.setAdapter(selectAdapter);
        binding.tvEdit.setOnClickListener(v -> {
            boolean show = selectAdapter.isShow();
            selectAdapter.setShow(!show);
            binding.tvSelectNum.setVisibility(show ? View.VISIBLE : View.GONE);
            binding.tvEdit.setText(show ? "撤销" : "修正");
        });
    }
}

在点击修正时调用适配器setShow(),然后操控底部的TextView显现,顺便修正一下tvEdit 文字,运转一下看看。

Android RecyclerView使用简述

③ 改写选中方位数据

  下面咱们需求点击Item时,修正数据,改写适配器,到达CheckBox选中或许撤销选中的意图,首要咱们需求修正SelectAdapter代码,如下所示:

	private OnItemClickListener listener;
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

增加点击监听回调办法,然后修正onCreateViewHolder()办法中的代码,如下所示:

	@NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ViewHolder viewHolder = new ViewHolder(ItemSelectRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
        viewHolder.binding.itemSelect.setOnClickListener(v -> {
            if (listener != null) {
                listener.onItemClick(v, viewHolder.getAdapterPosition());
            }
        });
        return viewHolder;
    }

便是增加一个点击工作罢了,下面回到RvDynamicallyChangeActivity,首要增加一个变量用来记载选中的个数,代码如下:

    private int selectNum = 0;

然后在initView()办法,代码如下所示:

	private void initView() {
        back(binding.materialToolbar);
        List<SelectBean> selects = getSelects();
        SelectAdapter selectAdapter = new SelectAdapter(selects);
        selectAdapter.setOnItemClickListener((view, position) -> {
            boolean select = selects.get(position).isSelect();
            //更改数据
            selects.get(position).setSelect(!select);
            //改写适配器
            selectAdapter.notifyItemChanged(position);
            if (!select) selectNum++;
            else selectNum--;
            binding.tvSelectNum.setText(String.format(Locale.getDefault(), "选中%d个", selectNum));
        });
        binding.rvText.setLayoutManager(new LinearLayoutManager(this));
        binding.rvText.setAdapter(selectAdapter);
        ...
    }

  省略号表明之前的tvEdit点击工作,这儿修正的中心内容便是适配器item的点击工作,点击时获取当时方位对应数据的选中状况,然后更改选中状况,经过notifyItemChanged()表明改写适配器数据,不过这儿只改写当时方位的数据,然后记载选中的个数,最终显现选中个数,便是这么简略,下面咱们运转一下看看。

Android RecyclerView使用简述

  那么到这儿就完了吗?其实还没有,咱们还需求注意到这个修正和撤销的处理,例如我现在是修正状况下,我挑选了几个,然后我不撤销勾选,而是推出修正,那么这时分则需求在推出修正的时分也清空一切选中的Item,而在修正的情况下才能选中。

首要在RvDynamicallyChangeActivity中界说一个变量

private boolean show = false;

然后修正Item点击中工作中加上一个判别,代码如下所示:

		selectAdapter.setOnItemClickListener((view, position) -> {
            if (!show) {
                boolean select = selects.get(position).isSelect();
                //更改数据
                selects.get(position).setSelect(!select);
                //改写适配器
                selectAdapter.notifyItemChanged(position);
                if (!select) selectNum++;
                else selectNum--;
                binding.tvSelectNum.setText(String.format(Locale.getDefault(), "选中%d个", selectNum));
            }
        });

然后修正tvEdit点击工作,代码如下:

		binding.tvEdit.setOnClickListener(v -> {
            show = selectAdapter.isShow();
            selectAdapter.setShow(!show);
            binding.tvSelectNum.setVisibility(show ? View.GONE : View.VISIBLE);
            binding.tvEdit.setText(show ? "修正" : "撤销");
            boolean cancel = !show;
            if (!cancel) {
                for (SelectBean select : selects) {
                    select.setSelect(false);
                }
                selectAdapter.notifyDataSetChanged();
                selectNum = 0;
                binding.tvSelectNum.setText(String.format(Locale.getDefault(), "选中%d个", selectNum));
            }
        });

  这儿的代码便是撤销的时分遍历列表的每一项,设置状况为false,然后经过notifyDataSetChanged()办法改写适配器一切数据,最终修正一下选中的数字和显现文字,这样就完毕了,看看作用图怎么。

Android RecyclerView使用简述

九、RecyclerView左右滑动和上下拖动

  在操作RecyclerView的时分,咱们还会有例如Item侧滑删除这样的操作,或许上下拖动更改Item的方位。下面来看看怎样做,首要相同是增加进口,说实话这部分代码我是真的不想加,可是我又忧虑有人看不懂,所以仍是加上吧。在activity_main.xml中增加一个按钮,代码如下:

	<Button
        android:id="@+id/btn_rv_swipe_drag"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="RecyclerView 左右滑动和上下拖动"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_rv_dynamically_change_data" />

然后在MainActivity中onCreate()办法中增加如下代码:

	binding.btnRvSwipeDrag.setOnClickListener(v -> jumpActivity(RvSwipeDragActivity.class));

下面在com.llw.recyclerviewdemo包下新建RvSwipeDragActivity,对应布局activity_rv_swipe_drag.xml,布局代码如下:

<?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=".RvSwipeDragActivity">
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIcon="@drawable/ic_back"
        app:title="RecyclerView 滑动和拖动"
        app:titleTextColor="@color/white" />
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_simple"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

这儿的适配器和数据Bean我就不需求从头创立了,直接用之前写好的BasicAdapter就能够了。

① 显现数据

首要咱们先显现数据列表,修正RvSwipeDragActivity中的代码,如下所示:

public class RvSwipeDragActivity extends BasicActivity {
    private ActivityRvSwipeDragBinding binding;
    private final List<String> lists = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityRvSwipeDragBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        initView();
    }
    private void initView() {
        back(binding.materialToolbar);
        lists.addAll(getStrings());
        //获取适配器实例
        BasicAdapter basicAdapter = new BasicAdapter(lists);
        final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //装备布局管理器
        binding.rvSimple.setLayoutManager(linearLayoutManager);
        //装备适配器
        binding.rvSimple.setAdapter(basicAdapter);
    }
}

  这个代码就很简略了,相信你现已见到过很屡次了,而增加滑动或许拖动的操作其实是很简略的,主要便是ItemTouchHelper这个类,下面咱们先完结左右滑动。

② ItemTouchHelper

在initView()增加如下代码:

		ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
            @Override
            public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
                return 0;
            }
            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
                return false;
            }
            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            }
        });
        //关联recyclerView
        helper.attachToRecyclerView(binding.rvSimple);

  在这儿经过完结ItemTouchHelper.Callback(),重写里边的三个办法,getMovementFlags()办法用于获取移动标志,例如标志有上下左右,一般滑动时左右,拖动是上下左右。onMove()办法用于拖动回调,onSwiped()办法用于滑动回调。

最终经过获取的helper实例,然后关联RecyclerView。

③ Item左右滑动

要完结左右滑动,首要需求设置移动标志位,也便是说需求修正getMovementFlags()办法的回来值,代码如下:

	@Override
	public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
    	//操控快速滑动的方向
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(0, swipeFlags);
	}

  这儿设置滑动的方向,运用makeMovementFlags()办法,里边传入了两个参数,第一个参数是拖动标识,第一个参数是滑动标志,设置为0便是不启用。

int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;

  这儿的swipeFlags的值是能够组合的,你是单独设置ItemTouchHelper.START或许ItemTouchHelper.END,也能够组合运用,START表明像左滑动,运用LEFT也行,END表明向右滑动,也能够运用RIGHT。

现在能够左右滑动了,那么滑动回调中咱们需求做什么?需求移除列表数据,更新适配器,修正onSwiped()办法,代码如下:

	@Override
	public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
		int adapterPosition = viewHolder.getAdapterPosition();
		lists.remove(adapterPosition);
		basicAdapter.notifyItemRemoved(adapterPosition);
	}

这儿看这个运用的notifyItemRemoved()办法作为适配器移除数据,下面运转看看作用。

Android RecyclerView使用简述

滑动超越屏幕中间后动作就不能回弹了,才会履行滑动回调,下面咱们增加上下拖动。

④ Item上下拖动

  增加拖动需求相同需求设置移动标志。修正getMovementFlags()办法,代码如下所示:

	@Override
	public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
    	//操控拖拽的方向
		int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END;
		//操控快速滑动的方向
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
	}

这儿设置了拖拽的标识位,下面便是在拖动回调办法onMove(),完结拖动item的方位的替换,修正代码如下所示:

	@Override
	public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
    	if (lists.size() > 0) {
        	//获取被拖拽的Item的Position
            int from = viewHolder.getAdapterPosition();
            //获取目标Item的Position
            int endPosition = target.getAdapterPosition();
            //交流List调集中两个元素的方位
            Collections.swap(lists, from, endPosition);
            //交流界面上两个Item的方位
            basicAdapter.notifyItemMoved(from, endPosition);
    	}
		return true;
	}

这儿的notifyItemMoved()办法便是用于拖动,修正单个Item,现在咱们一起支撑了滑动和拖动,运转一下看看作用。

Android RecyclerView使用简述

十、源码

假如源码对你有协助的话,不妨Star或Fork一下~

Github地址:RecyclerViewDemo