android 分页加载坑,Android RecyclerView的刷新分页的实现

在开发中常常使用到刷新分页,这里实现一个 RecyclerView 的简单的刷新分页操作,测试效果见文末,实现过程参考如下:

实现思路

加载更多数据使用到 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);

}

}

代码参考

主布局

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:id="@+id/rv"

android:layout_width="match_parent"

android:layout_height="match_parent">

Item布局

/**item.xml**/

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:padding="5dp">

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"/>

/**item_footer.xml**/

android:orientation="horizontal"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center_horizontal">

style="?android:attr/progressBarStyleSmall"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/progressBar" />

android:text="正在努力加载中,请稍后..."

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/textView" />

Adapter

这里使用了 RecyclerView 根据不同的 ViewType 加载多种布局的用法,使用时根据不同的布局创建不同的 ViewHolder , 然后根据不同的 Viewholder 为对应的 Item 添加数据,注意 getItemViewType() 方法的用法,Adapter 代码参考如下:

/**

* Created by jzman on 2017/6/04

* RecycleView的Adapter

*/

public class RvAdapter1 extends RecyclerView.Adapter 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 mList;

public RvAdapter1() {}

public RvAdapter1(Context mContext, ArrayList mList) {

this.mContext = mContext;

this.mList = mList;

}

public void setmList(ArrayList 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 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) msg.obj;

adapter.setmList(arrayList);

adapter.notifyDataSetChanged();

break;

}

}

};

}

测试效果

dde8fc3a08f44f056eba72e201b8385f.gif

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值