Android 循环视图加载更多内容,无尽滚动

在本教程中,我们将讨论并在我们的Android应用程序中实现无限滚动或无限滚动。无限滚动从DB/Server获取下一组行,同时显示加载图标,这在许多应用程序中都很常见,如Facebook、Twitter。建议您在继续操作之前先阅读this教程。

Android回收查看加载更多内容

为了在获取下一组项目时在RecclerView的底部显示加载图标,我们需要在RecEconerView Adapter中使用多种视图类型。这是如何实现的? 通常在简单的RecEconerView中,我们将元素从数据结构加载到适配器。为了在RecillerView的底部显示加载图标视图,我们首先需要在数据结构的末尾添加一个空元素。** 为什么为空?** 以便将该元素与其他元素区分开来,并显示不同的视图类型行。添加空元素后,我们将新元素通知适配器并获取下一组元素。一旦获得了下一组元素,我们就删除空元素并将下一组元素添加到数据结构的底部。下图演示了在RecEconerView及其适配器中实际发生的情况。安卓回收站查看加载更多flow

为了检测到用户已经滚动到RecillerView的末尾,我们需要在RecclerView上实现OnScrollListener()

说够了。让我们来编码吧。在接下来的小节中,我们将通过填充一个字符串列表并在延迟后使用处理程序加载下一组列表来演示在RecEconerView上无休止地滚动。

项目结构

安卓回收站加载更多项目structure

代码

Active_main.xml布局的代码如下所示:

 1<?xml version="1.0" encoding="utf-8"?>
 2<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
 3    xmlns:app="https://schemas.android.com/apk/res-auto"
 4    xmlns:tools="https://schemas.android.com/tools"
 5    android:layout_width="match_parent"
 6    android:layout_height="match_parent"
 7    tools:context=".MainActivity">
 8
 9    <android.support.v7.widget.RecyclerView
10        android:id="@+id/recyclerView"
11        android:layout_width="match_parent"
12        android:layout_height="match_parent"
13        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
14        app:layout_constraintBottom_toBottomOf="parent"
15        app:layout_constraintLeft_toLeftOf="parent"
16        app:layout_constraintRight_toRightOf="parent"
17        app:layout_constraintTop_toTopOf="parent" />
18
19</android.support.constraint.ConstraintLayout>

循环视图行的布局在Item_row.xml文件中定义,如下所示:

 1<?xml version="1.0" encoding="utf-8"?>
 2<android.support.v7.widget.CardView xmlns:android="https://schemas.android.com/apk/res/android"
 3    xmlns:app="https://schemas.android.com/apk/res-auto"
 4    android:layout_width="match_parent"
 5    android:layout_height="wrap_content"
 6    app:cardElevation="8dp"
 7    app:cardUseCompatPadding="true">
 8
 9    <TextView
10        android:id="@+id/tvItem"
11        android:layout_width="match_parent"
12        android:layout_height="wrap_content"
13        android:padding="16dp"
14        android:text="Item X" />
15
16</android.support.v7.widget.CardView>

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

 1<?xml version="1.0" encoding="utf-8"?>
 2<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
 3    android:layout_width="match_parent"
 4    android:layout_height="wrap_content"
 5    android:layout_margin="8dp"
 6    android:orientation="vertical">
 7
 8    <ProgressBar
 9        android:id="@+id/progressBar"
10        android:layout_width="wrap_content"
11        android:layout_height="wrap_content"
12        android:layout_gravity="center_horizontal"
13        android:indeterminate="true"
14        android:paddingLeft="8dp"
15        android:paddingRight="8dp"
16        />
17
18</LinearLayout>

下面给出了RecillerViewAdapter.Java类的代码:

 1package com.journaldev.androidrecyclerviewloadmore;
 2
 3import android.support.annotation.NonNull;
 4import android.support.v7.widget.RecyclerView;
 5import android.view.LayoutInflater;
 6import android.view.View;
 7import android.view.ViewGroup;
 8import android.widget.ProgressBar;
 9import android.widget.TextView;
10
11import java.util.List;
12
13public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
14
15    private final int VIEW_TYPE_ITEM = 0;
16    private final int VIEW_TYPE_LOADING = 1;
17
18    public List<String> mItemList;
19
20    public RecyclerViewAdapter(List<String> itemList) {
21
22        mItemList = itemList;
23    }
24
25    @NonNull
26    @Override
27    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
28        if (viewType == VIEW_TYPE_ITEM) {
29            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
30            return new ItemViewHolder(view);
31        } else {
32            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false);
33            return new LoadingViewHolder(view);
34        }
35    }
36
37    @Override
38    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
39
40        if (viewHolder instanceof ItemViewHolder) {
41
42            populateItemRows((ItemViewHolder) viewHolder, position);
43        } else if (viewHolder instanceof LoadingViewHolder) {
44            showLoadingView((LoadingViewHolder) viewHolder, position);
45        }
46
47    }
48
49    @Override
50    public int getItemCount() {
51        return mItemList == null ? 0 : mItemList.size();
52    }
53
54    /**
55     * The following method decides the type of ViewHolder to display in the RecyclerView
56     *
57     * @param position
58     * @return
59     */
60    @Override
61    public int getItemViewType(int position) {
62        return mItemList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
63    }
64
65    private class ItemViewHolder extends RecyclerView.ViewHolder {
66
67        TextView tvItem;
68
69        public ItemViewHolder(@NonNull View itemView) {
70            super(itemView);
71
72            tvItem = itemView.findViewById(R.id.tvItem);
73        }
74    }
75
76    private class LoadingViewHolder extends RecyclerView.ViewHolder {
77
78        ProgressBar progressBar;
79
80        public LoadingViewHolder(@NonNull View itemView) {
81            super(itemView);
82            progressBar = itemView.findViewById(R.id.progressBar);
83        }
84    }
85
86    private void showLoadingView(LoadingViewHolder viewHolder, int position) {
87        //ProgressBar would be displayed
88
89    }
90
91    private void populateItemRows(ItemViewHolder viewHolder, int position) {
92
93        String item = mItemList.get(position);
94        viewHolder.tvItem.setText(item);
95
96    }
97
98}

getItemViewType是我们检查列表中每个元素的位置。如果元素为空,则将视图类型设置为1,否则设置为0。根据View类型,我们实例化onCreateViewHolder中的ViewHolder。在onBindViewHolder中,我们检查ViewHolder实例的类型并相应地填充该行。让我们看一下MainActivity.java类,我们在其中实例化上述Adapter。

 1package com.journaldev.androidrecyclerviewloadmore;
 2
 3import android.os.Handler;
 4import android.support.annotation.NonNull;
 5import android.support.v7.app.AppCompatActivity;
 6import android.os.Bundle;
 7import android.support.v7.widget.LinearLayoutManager;
 8import android.support.v7.widget.RecyclerView;
 9
10import java.util.ArrayList;
11
12public class MainActivity extends AppCompatActivity {
13
14    RecyclerView recyclerView;
15    RecyclerViewAdapter recyclerViewAdapter;
16    ArrayList<String> rowsArrayList = new ArrayList<>();
17
18    boolean isLoading = false;
19
20    @Override
21    protected void onCreate(Bundle savedInstanceState) {
22        super.onCreate(savedInstanceState);
23        setContentView(R.layout.activity_main);
24
25        recyclerView = findViewById(R.id.recyclerView);
26        populateData();
27        initAdapter();
28        initScrollListener();
29
30    }
31
32    private void populateData() {
33        int i = 0;
34        while (i < 10) {
35            rowsArrayList.add("Item " + i);
36            i++;
37        }
38    }
39
40    private void initAdapter() {
41
42        recyclerViewAdapter = new RecyclerViewAdapter(rowsArrayList);
43        recyclerView.setAdapter(recyclerViewAdapter);
44    }
45
46    private void initScrollListener() {
47        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
48            @Override
49            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
50                super.onScrollStateChanged(recyclerView, newState);
51            }
52
53            @Override
54            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
55                super.onScrolled(recyclerView, dx, dy);
56
57                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
58
59                if (!isLoading) {
60                    if (linearLayoutManager != null && linearLayoutManager.findLastCompletelyVisibleItemPosition() == rowsArrayList.size() - 1) {
61                        //bottom of list!
62                        loadMore();
63                        isLoading = true;
64                    }
65                }
66            }
67        });
68
69    }
70
71    private void loadMore() {
72        rowsArrayList.add(null);
73        recyclerViewAdapter.notifyItemInserted(rowsArrayList.size() - 1);
74
75        Handler handler = new Handler();
76        handler.postDelayed(new Runnable() {
77            @Override
78            public void run() {
79                rowsArrayList.remove(rowsArrayList.size() - 1);
80                int scrollPosition = rowsArrayList.size();
81                recyclerViewAdapter.notifyItemRemoved(scrollPosition);
82                int currentSize = scrollPosition;
83                int nextLimit = currentSize + 10;
84
85                while (currentSize - 1 < nextLimit) {
86                    rowsArrayList.add("Item " + currentSize);
87                    currentSize++;
88                }
89
90                recyclerViewAdapter.notifyDataSetChanged();
91                isLoading = false;
92            }
93        }, 2000);
94
95    }
96}

initScrollListener是上述代码中最重要的方法。在这里,我们检查RecillerView的滚动状态,如果最下面的项可见,则显示加载视图并填充下一个列表。上述实际应用程序的输出如下所示:结束了本教程。您可以从下面的链接下载该项目:

AndroidClerViewLoadMore

GitHub项目Link

Published At
Categories with 技术
Tagged with
comments powered by Disqus