Android RecyclerView加载更多,无限滚动

In this tutorial, we’ll be discussing and implementing Endless Scrolling or Infinite Scroll on RecyclerView in our Android Application. The infinite scrolling in which the next set of rows are fetched from the DB/Server while showing a loading icon is commonly seen in many applications such as Facebook, Twitter.

在本教程中,我们将在Android应用程序中的RecyclerView上讨论并实现“无限滚动”或“无限滚动”。 在许多应用程序(例如Facebook,Twitter)中,通常会看到无限滚动,其中无限滚动是在显示加载图标的同时从DB / Server获取下一组行。

It’s recommended to go through this tutorial before proceeding ahead.

建议先阅读教程,然后再继续。

Android RecyclerView加载更多 (Android RecyclerView Load More)

In order to show Loading icon at the bottom of RecyclerView while the next set of items are fetched, we need to use Multiple View Types in our RecyclerView Adapter.

为了在获取下一组项目时在RecyclerView的底部显示“正在加载”图标,我们需要在RecyclerView适配器中使用“多种视图类型”。

How is this implemented?

如何实施?

Typically in a simple RecyclerView, we load elements to the adapter from a Data Structure.

通常,在简单的RecyclerView中,我们从数据结构将元素加载到适配器。

In order to show the loading icon view at the bottom of the RecyclerView, we need to first add a NULL element to the end of the Data Structure.

为了在RecyclerView的底部显示加载图标视图,我们需要首先在数据结构的末尾添加一个NULL元素。

Why NULL?

为什么为NULL?

In order to differentiate that element from the rest of the elements and show a different view type row.

为了将该元素与其余元素区分开,并显示不同的视图类型行。

After adding a null, we notify the adapter the of the new element and fetch the next set of elements.

添加空值后,我们将新元素通知适配器,并获取下一组元素。

Once the next set of elements is obtained, we remove the NULL element and add the next set to the bottom of the Data Structure.

一旦获得下一组元素,我们将删除NULL元素,并将下一组元素添加到数据结构的底部。

Following diagram demonstrates what actually happens in the RecyclerView and its Adapter.

下图演示了RecyclerView及其适配器实际发生的情况。

OnScrollListener() on the RecyclerView. OnScrollListener()

Enough Talk. Let’s code.

聊够了。 让我们编码。

In the following section, we’ll demonstrate Endless Scrolling on RecyclerView by populating a List of Strings and loading the next set of List after a delay using Handlers.

在下一节中,我们将通过填充字符串列表并使用Handlers在延迟后加载下一组List来演示RecyclerView上的无尽滚动。

项目结构 (Project Structure)

(Code)

The code for the activity_main.xml layout is given below:

下面给出了activity_main.xml布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

The layout for the rows of the RecyclerView is defined in item_row.xml file as shown below:

RecyclerView的行的布局在item_row.xml文件中定义,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardElevation="8dp"
    app:cardUseCompatPadding="true">


    <TextView
        android:id="@+id/tvItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:text="Item X" />

</android.support.v7.widget.CardView>

The layout for the loading view is defined in the item_loading.xml file as shown below:

加载视图的布局在item_loading.xml文件中定义,如下所示:

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

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:indeterminate="true"
        android:paddingLeft="8dp"
        android:paddingRight="8dp"
        />

</LinearLayout>

The code for the RecyclerViewAdapter.java class is given below:

下面给出了RecyclerViewAdapter.java类的代码:

package com.journaldev.androidrecyclerviewloadmore;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.util.List;

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

    private final int VIEW_TYPE_ITEM = 0;
    private final int VIEW_TYPE_LOADING = 1;

    public List<String> mItemList;


    public RecyclerViewAdapter(List<String> itemList) {

        mItemList = itemList;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == VIEW_TYPE_ITEM) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
            return new ItemViewHolder(view);
        } else {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false);
            return new LoadingViewHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {

        if (viewHolder instanceof ItemViewHolder) {

            populateItemRows((ItemViewHolder) viewHolder, position);
        } else if (viewHolder instanceof LoadingViewHolder) {
            showLoadingView((LoadingViewHolder) viewHolder, position);
        }

    }

    @Override
    public int getItemCount() {
        return mItemList == null ? 0 : mItemList.size();
    }

    /**
     * The following method decides the type of ViewHolder to display in the RecyclerView
     *
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        return mItemList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
    }


    private class ItemViewHolder extends RecyclerView.ViewHolder {

        TextView tvItem;

        public ItemViewHolder(@NonNull View itemView) {
            super(itemView);

            tvItem = itemView.findViewById(R.id.tvItem);
        }
    }

    private class LoadingViewHolder extends RecyclerView.ViewHolder {

        ProgressBar progressBar;

        public LoadingViewHolder(@NonNull View itemView) {
            super(itemView);
            progressBar = itemView.findViewById(R.id.progressBar);
        }
    }

    private void showLoadingView(LoadingViewHolder viewHolder, int position) {
        //ProgressBar would be displayed

    }

    private void populateItemRows(ItemViewHolder viewHolder, int position) {

        String item = mItemList.get(position);
        viewHolder.tvItem.setText(item);

    }


}

getItemViewType is where we check each element of the List. If the element is NULL we set the view type as 1 else 0.

getItemViewType是我们检查List的每个元素的地方。 如果元素为NULL,则将视图类型设置为1,否则设置为0。

Based on the View type we instantiate the ViewHolder in the onCreateViewHolder.

基于View类型,我们在onCreateViewHolder中实例化ViewHolder。

Inside the onBindViewHolder we check the type of ViewHolder instance and populate the row accordingly.

onBindViewHolder内部,我们检查ViewHolder实例的类型并相应地填充行。

Let’s look at the MainActivity.java class where we instantiate the above Adapter.

让我们看一下我们实例化上面的Adapter的MainActivity.java类。

package com.journaldev.androidrecyclerviewloadmore;

import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    RecyclerViewAdapter recyclerViewAdapter;
    ArrayList<String> rowsArrayList = new ArrayList<>();

    boolean isLoading = false;

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

        recyclerView = findViewById(R.id.recyclerView);
        populateData();
        initAdapter();
        initScrollListener();


    }

    private void populateData() {
        int i = 0;
        while (i < 10) {
            rowsArrayList.add("Item " + i);
            i++;
        }
    }

    private void initAdapter() {

        recyclerViewAdapter = new RecyclerViewAdapter(rowsArrayList);
        recyclerView.setAdapter(recyclerViewAdapter);
    }

    private void initScrollListener() {
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();

                if (!isLoading) {
                    if (linearLayoutManager != null && linearLayoutManager.findLastCompletelyVisibleItemPosition() == rowsArrayList.size() - 1) {
                        //bottom of list!
                        loadMore();
                        isLoading = true;
                    }
                }
            }
        });


    }

    private void loadMore() {
        rowsArrayList.add(null);
        recyclerViewAdapter.notifyItemInserted(rowsArrayList.size() - 1);


        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                rowsArrayList.remove(rowsArrayList.size() - 1);
                int scrollPosition = rowsArrayList.size();
                recyclerViewAdapter.notifyItemRemoved(scrollPosition);
                int currentSize = scrollPosition;
                int nextLimit = currentSize + 10;

                while (currentSize - 1 < nextLimit) {
                    rowsArrayList.add("Item " + currentSize);
                    currentSize++;
                }

                recyclerViewAdapter.notifyDataSetChanged();
                isLoading = false;
            }
        }, 2000);


    }
}

initScrollListener is the most important method in the above code.
It’s there where we check the scrolled state of the RecyclerView and if the bottom-most item is visible we show the loading view and populate the next list.

initScrollListener是以上代码中最重要的方法。
在这里,我们检查RecyclerView的滚动状态,如果最底部的项目可见,我们将显示加载视图并填充下一个列表。

The output of the above application in action is given below:

上面应用程序的输出如下:

That brings an end to this tutorial. You can download the project from the link below:

这样就结束了本教程。 您可以从下面的链接下载项目:

翻译自: https://www.journaldev.com/24041/android-recyclerview-load-more-endless-scrolling

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你想让整个页面可以滚动和下拉刷新,你可以使用下拉刷新控件 SwipeRefreshLayout。将 RecyclerView 放在 SwipeRefreshLayout 中,就可以通过下拉刷新来更新 RecyclerView 中的数据。同时,SwipeRefreshLayout 也会自动处理下拉刷新时的滑动操作。 以下是一个示例代码,展示如何在 Activity 中使用 SwipeRefreshLayout 和 RecyclerView: ```xml <androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> ``` ```java public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener { private SwipeRefreshLayout swipeRefreshLayout; private RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout); swipeRefreshLayout.setOnRefreshListener(this); recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new MyAdapter()); } @Override public void onRefresh() { // 执行下拉刷新操作 // 更新 RecyclerView 中的数据 // 更新完成后,调用 swipeRefreshLayout.setRefreshing(false) 结束下拉刷新状态 } private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { // 实现 RecyclerView.Adapter 的其他方法 @Override public int getItemCount() { return 0; // 返回列表中的数据数量 } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // 创建 ViewHolder,加载 item 布局文件 return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false)); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { // 绑定 ViewHolder 中的数据 } } private static class MyViewHolder extends RecyclerView.ViewHolder { // ViewHolder 中的控件 public MyViewHolder(View itemView) { super(itemView); // 初始化 ViewHolder 中的控件 } } } ``` 在 `onRefresh` 方法中执行下拉刷新操作,更新 RecyclerView 中的数据。更新完成后,调用 `swipeRefreshLayout.setRefreshing(false)` 结束下拉刷新状态。这样,整个页面就可以滚动和下拉刷新了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值