在开发中常常使用到刷新分页,这里实现一个 RecyclerView 的简单的刷新分页操作。
RecyclerView的使用请参考:RecyclerView的简单使用
RecyclerView的 Item 的单击事件请参考:RecyclerView的 Item 的单击事件
实现思路
加载更多数据使用到 RecyclerView 加载多种布局,根据 ViewType 判断加载数据 Item 还是加载 FooterItem ;
通过线程模拟加载数据;
为 RecyclerView 添加 addOnScrollListener 事件来监听用户的滑动操作;
根据用户滑动状态以及具体情况开始加载数据
通知数据更新;
如何获得 firstVisibleItemPosition
为了能够在数据加载中动态判断什么时候加载数据,需要知道屏幕上显示的第一个可见的 Item 的位置,当然了这里使用的是布局管理器是 LinearLayoutManager ,这样查找屏幕上第一个可见的 Item 就显得容易多了,下面介绍一些 LinearLayoutManager 的四个方法:
findFirstVisibleItemPosition()
获得屏幕上第一个可见 Item 的 position,只要该 Item 有一部分可见,那么返回的 position 就是该Item 的 position。
findFirstCompletelyVisibleItemPosition()
获得屏幕上第一个完整可见的 Item 的 position,只要该 Item 有一部分不可见,那么返回的 position 就是该 Item 对应的下一个能显示完整的 Item 的position。
findLastVisibleItemPosition()
获得屏幕上最后一个可见 Item 的 position,只要该 Item 有一部分可见,那么返回的 position 就是该Item 的 position。
findLastCompletelyVisibleItemPosition()
获得屏幕上最后一个完整可见的 Item 的 position,只要该 Item 有一部分不可见,那么返回的 position 就是该 Item 对应的上一个能显示完整的 Item 的position。
准备数据
/**
* 初始化数据
* @return
*/
public void initData(){ for (int i=0;i<30;i++){
arrayList.add("第"+i+"条数据");
}
}
/**
* 线程模拟加载数据
*/
class LoadDataThread extends Thread{ @Override
public void run() {
initData(); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} //通知主线程更新数据
Message message = handler.obtainMessage();
message.what = UPDATE_DATA;
message.obj = arrayList;
handler.sendMessage(message);
}
}代码参考
主布局
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.manu.mrecyclerview.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView></LinearLayout>
Item布局
/**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" android:padding="5dp"> <TextView android:id="@+id/tv_recycle" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="data" android:background="#cac3c3" android:padding="10dp" android:textSize="20sp"/></LinearLayout>
/**item_footer.xml**/<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal"> <ProgressBar style="?android:attr/progressBarStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar" /> <TextView android:text="正在努力加载中,请稍后..." android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textView" /></LinearLayout>
Adapter
这里使用了 RecyclerView 根据不同的 ViewType 加载多种布局的用法,使用时根据不同的布局创建不同的 ViewHolder , 然后根据不同的 Viewholder 为对应的 Item 添加数据,注意 getItemViewType() 方法的用法,Adapter 代码参考如下:
/**
* Created by jzman on 2017/6/04
* RecycleView的Adapter
*/public class RvAdapter1 extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements
View.OnClickListener{ private static final int ITEM_FOOTER = 0x1; private static final int ITEM_DATA = 0x2; private Context mContext; private RecyclerView recyclerView; private ArrayList<String> mList; public RvAdapter1() {} public RvAdapter1(Context mContext, ArrayList<String> mList) { this.mContext = mContext; this.mList = mList;
} public void setmList(ArrayList<String> mList) { this.mList = mList;
} /**
* 用于创建ViewHolder
* @param parent
* @param viewTypez
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view ;
RecyclerView.ViewHolder vh = null; switch (viewType){ case ITEM_DATA:
view = LayoutInflater.from(mContext).inflate(R.layout.item,null);
view.setOnClickListener(this);
vh = new DataViewHolder(view); //使用代码设置宽高(xml布局设置无效时)
view.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)); break; case ITEM_FOOTER:
view = LayoutInflater.from(mContext).inflate(R.layout.item_footer,null); //使用代码设置宽高(xml布局设置无效时)
vh = new FooterViewHolder(view);
view.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)); break;
} return vh;
} /**
* 获取Item的View类型
* @param position
* @return
*/
@Override
public int getItemViewType(int position) { //根据 Item 的 position 返回不同的 Viewtype
if (position == (getItemCount())-1){ return ITEM_FOOTER;
}else{ return ITEM_DATA;
}
} /**
* 绑定数据
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof DataViewHolder){
DataViewHolder dataViewHolder = (DataViewHolder) holder;
dataViewHolder.tv_data.setText(mList.get(position));
}else if (holder instanceof FooterViewHolder){
}
} /**
* 选项总数
* @return
*/
@Override
public int getItemCount() { return mList.size()+1;
} @Override
public void onClick(View view) { //根据RecyclerView获得当前View的位置
int position = recyclerView.getChildAdapterPosition(view); //程序执行到此,会去执行具体实现的onItemClick()方法
if (onItemClickListener!=null){
onItemClickListener.onItemClick(recyclerView,view,position,mList.get(position));
}
} /**
* 创建ViewHolder
*/
public static class DataViewHolder extends RecyclerView.ViewHolder{
TextView tv_data; public DataViewHolder(View itemView) { super(itemView);
tv_data = (TextView) itemView.findViewById(R.id.tv_recycle);
}
} /**
* 创建footer的ViewHolder
*/
public static class FooterViewHolder extends RecyclerView.ViewHolder{ public FooterViewHolder(View itemView) { super(itemView);
}
} private OnItemClickListener onItemClickListener; public void setOnItemClickListener(OnItemClickListener onItemClickListener){ this.onItemClickListener = onItemClickListener;
} /**
* 定义RecyclerView选项单击事件的回调接口
*/
public interface OnItemClickListener{ //参数(父组件,当前单击的View,单击的View的位置,数据)
void onItemClick(RecyclerView parent,View view, int position, String data);
} /**
* 将RecycleView附加到Adapter上
*/
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); this.recyclerView= recyclerView;
} /**
* 将RecycleView从Adapter解除
*/
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); this.recyclerView = null;
}
}MainActivity
这里主要注意 rv.addOnScrollListener(new OnScrollListener() ...里面的具体实现,MainActivity 代码参考如下:
/**
* Created by jzman on 2017/6/04 0013.
*/public class MainActivity extends AppCompatActivity { private static final int UPDATE_DATA = 0x3;
private RecyclerView rv;
RvAdapter1 adapter; private ArrayList<String> arrayList = new ArrayList<>(); //加载更多数据时最后一项的索引
private int lastLoadDataItemPosition; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rv = (RecyclerView) findViewById(R.id.rv); //设置布局管理器
rv.setLayoutManager(new LinearLayoutManager(this));//线性// rv.setLayoutManager(new GridLayoutManager(this,4));//线性// rv.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));//线性
initData();
adapter = new RvAdapter1(this,arrayList);
adapter.setOnItemClickListener(new RvAdapter1.OnItemClickListener() { @Override
public void onItemClick(RecyclerView parent, View view, int position, String data) {
Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
}
});
rv.addOnScrollListener(new OnScrollListener() { @Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (newState == SCROLL_STATE_IDLE &&
lastLoadDataItemPosition == adapter.getItemCount()){ new LoadDataThread().start();
}
} @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager){
LinearLayoutManager manager = (LinearLayoutManager) layoutManager; int firstVisibleItem = manager.findFirstVisibleItemPosition(); int l = manager.findLastCompletelyVisibleItemPosition();
lastLoadDataItemPosition = firstVisibleItem+(l-firstVisibleItem)+1;
}
}
});
rv.setAdapter(adapter);
} /**
* 初始化数据
* @return
*/
public void initData(){ for (int i=0;i<25;i++){
arrayList.add("第"+i+"条数据");
}
} /**
* 线程模拟加载数据
*/
class LoadDataThread extends Thread{ @Override
public void run() {
initData(); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = handler.obtainMessage();
message.what = UPDATE_DATA;
message.obj = arrayList;
handler.sendMessage(message);
}
} private Handler handler = new Handler(){ @Override
public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case UPDATE_DATA:
arrayList = (ArrayList<String>) msg.obj;
adapter.setmList(arrayList);
adapter.notifyDataSetChanged(); break;
}
}
};
}测试效果
共同學習,寫下你的評論
評論加載中...
作者其他優質文章
