将不确定的进度条作为页脚放置在RecyclerView网格中
如何获得不确定的循环指标“向上滚动以加载更多”在网格RecycleView?
在这里描述的模式: http : //www.google.com/design/spec/components/progress-activity.html#progress-activity-behavior “两阶段负载”和“例2:向上滚动以加载更多“示例video。
我试图用新的RecyclerView完成这个工作,但是我找不到一个“不要太冒昧”的方法来做到这一点,首先是因为没有办法添加一个覆盖整个网格的页脚。 有什么build议么?
这样做很简单。
解决scheme是使用与GridLayoutManager
相同的LinearLayoutManager
方法,然后在LayoutManager
上使用setSpanSizeLookup
LayoutManager
如下所示:
mLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { switch(myAdapter.getItemViewType(position)){ case MyAdapter.VIEW_TYPES.Product: return 1; case MyAdapter.VIEW_TYPES.Progress: return 2; //number of columns of the grid default: return -1; } } });
这将自动使项目覆盖整个网格的行(如果行不完全是空的,则该项目进入下一行)。
注意下面的解决scheme有一些潜在的问题和限制,修改后的解决scheme请检查这一个 添加项目无尽滚动RecyclerView ProgressBar在底部
这里是我最近提出的解决scheme:这个想法是让RecyclerView有两种types的项目,一种是我们平时的项目,另一种是进度条,然后我们需要监听滚动事件,然后决定是否加载更多并显示进度条。 所以从想法到示例代码
progress_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar" android:indeterminate="true" style="@android:style/Widget.Holo.ProgressBar" android:layout_gravity="center_horizontal"/> </LinearLayout>
activity_main.xml中
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:ring="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
EndlessRecyclerOnScrollListener.java
public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener { public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName(); private int previousTotal = 0; // The total number of items in the dataset after the last load private boolean loading = true; // True if we are still waiting for the last set of data to load. private int visibleThreshold = 1; // The minimum amount of items to have below your current scroll position before loading more. int firstVisibleItem, visibleItemCount, totalItemCount; private int current_page = 1; private LinearLayoutManager mLinearLayoutManager; public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) { this.mLinearLayoutManager = linearLayoutManager; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); visibleItemCount = recyclerView.getChildCount(); totalItemCount = mLinearLayoutManager.getItemCount(); firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition(); if (loading) { if (totalItemCount > previousTotal+1) { loading = false; previousTotal = totalItemCount; } } if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { // End has been reached // Do something current_page++; onLoadMore(current_page); loading = true; } } public abstract void onLoadMore(int current_page); }
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private final int VIEW_ITEM = 1; private final int VIEW_PROG = 0; private List<String> mDataset; public static class TextViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public TextViewHolder(View v) { super(v); mTextView = (TextView)v.findViewById(android.R.id.text1); } } public static class ProgressViewHolder extends RecyclerView.ViewHolder { public ProgressBar progressBar; public ProgressViewHolder(View v) { super(v); progressBar = (ProgressBar)v.findViewById(R.id.progressBar); } } public MyAdapter(List<String> myDataset) { mDataset = myDataset; } @Override public int getItemViewType(int position) { return mDataset.get(position)!=null? VIEW_ITEM: VIEW_PROG; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder vh; if(viewType==VIEW_ITEM) { View v = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); vh = new TextViewHolder(v); }else { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.progress_item, parent, false); vh = new ProgressViewHolder(v); } return vh; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if(holder instanceof TextViewHolder){ ((TextViewHolder)holder).mTextView.setText(mDataset.get(position)); }else{ ((ProgressViewHolder)holder).progressBar.setIndeterminate(true); } } @Override public int getItemCount() { return mDataset.size(); } }
最后是MainActivity.java
package virtoos.com.testapps; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import java.util.ArrayList; import java.util.List; public class MainActivity extends Activity { private RecyclerView mRecyclerView; private LinearLayoutManager mLayoutManager; private MyAdapter mAdapter; private final List<String> myDataset = new ArrayList<>(); private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new Handler(); addItems(20); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); mAdapter = new MyAdapter(myDataset); mRecyclerView.setAdapter(mAdapter); //mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager) { @Override public void onLoadMore(int current_page) { //add progress item myDataset.add(null); mAdapter.notifyItemInserted(myDataset.size()); handler.postDelayed(new Runnable() { @Override public void run() { //remove progress item myDataset.remove(myDataset.size() - 1); mAdapter.notifyItemRemoved(myDataset.size()); //add items one by one for (int i = 0; i < 15; i++) { myDataset.add("Item"+(myDataset.size()+1)); mAdapter.notifyItemInserted(myDataset.size()); } //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged(); } }, 2000); System.out.println("load"); } }); } }
这里是对RecylerView.Adapter的@Vilen Melkumyan回答的一个小修改,对我来说效果更好。 您可以使用您的EndlessRecyclerOnScrollListener
以任何方式加载数据,也可以随时启用或禁用页脚。
PS:它与GridLayoutManager
一起工作。
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private final int VIEW_TYPE_ITEM = 1; private final int VIEW_TYPE_PROGRESSBAR = 0; private boolean isFooterEnabled = true; private List<String> items; public static class TextViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public TextViewHolder(View v) { super(v); mTextView = (TextView)v.findViewById(android.R.id.text1); } } public static class ProgressViewHolder extends RecyclerView.ViewHolder { public ProgressBar progressBar; public ProgressViewHolder(View v) { super(v); progressBar = (ProgressBar)v.findViewById(R.id.progressBar); } } public MyRecyclerViewAdapter(List<String> myDataset) { items = myDataset; } @Override public int getItemCount() { return (isFooterEnabled) ? items.size() + 1 : items.size(); } @Override public int getItemViewType(int position) { return (isFooterEnabled && position >= items.size() ) ? VIEW_TYPE_PROGRESSBAR : VIEW_TYPE_ITEM; } /** * Enable or disable footer (Default is true) * * @param isEnabled boolean to turn on or off footer. */ public void enableFooter(boolean isEnabled){ this.isFooterEnabled = isEnabled; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder vh; if(viewType== VIEW_TYPE_ITEM) { View v = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); vh = new TextViewHolder(v); }else { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.progressbar, parent, false); vh = new ProgressViewHolder(v); } return vh; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if(holder instanceof ProgressViewHolder){ ((ProgressViewHolder)holder).progressBar.setIndeterminate(true); } else if(items.size() > 0 && position < items.size()) { ((TextViewHolder)holder).mTextView.setText(items.get(position)); } } }
我的2美分,和平!
在https://github.com/ramirodo/endless-recycler-view-adapter或https://bintray.com/ramiro/android/endless-recycler-view-adapter查看我的解决scheme。; 有一个例子,还有在您的项目中设置库的步骤。
您只需要通过实施所需的方法来扩展您的回收视图适配器。 您也可以设置进度页脚的布局。
您可以通过在代码中插入代码来简化Bronx的答案。
public class ArticleGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private final int VIEW_ITEM = 0; private final int VIEW_LOADING = 1; private Context mContext; private List<Article> mArticles = new ArrayList<>(); private RecyclerView mRecyclerView; private GridLayoutManager mManager; public ArticleGridAdapter(Context context, List<Article> articles, RecyclerView recyclerView) { this.mContext = context; this.mArticles = articles; this.mRecyclerView = recyclerView; this.mManager = (GridLayoutManager) recyclerView.getLayoutManager(); mManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return getItemViewType(position) == VIEW_LOADING ? mManager.getSpanCount() : 1; } }); } }