android加载网络提示错误,Android 下拉刷新上拉加载(解决item未满一页时的显示问题、添加网络错误等提示)...

最近项目中用到下拉刷新和上拉加载,于是在网上找了许多轮子,发现很多都有瑕疵,大多都没有解决当前item不满一页时,上拉加载的View一直显示的问题。之后自己尝试解决该问题,并完善了其他功能,就写了如下demo,看下面:

一、下拉刷新:

使用的是SwipeRefrshLayout,在support-v4兼容包下,作为官方的下拉刷新控件,其功能还很强大的,也不详细介绍了,网上的使用详解一大堆,这里讲一下基本使用方法:

setOnRefreshListener(OnRefreshListener):添加下拉刷新监听器

setRefreshing(boolean):显示或者隐藏刷新进度条

isRefreshing():检查是否处于刷新状态

setColorSchemeResources():设置进度条的颜色主题,最多设置四种。

然后在xml中:

android:id="@+id/sr_load_more"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/rv_load_more"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

Java代码中添加刷新事件:

mSrl=(SwipeRefreshLayout)findViewById(R.id.sr_load_more);

mSrl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {

@Override

public void onRefresh() {

// 调用刷新方法

}

});

效果:

33d246af5904

image

是不是很简单呢?具体使用可以去看下官方文档,下面我们来说上拉加载。

二、上拉加载:

首先,确定需求:

当RecyclerView加载时,只显示RecyclerView的item;

用户上拉,拉到最后一项item时,出现下拉刷新的footerView,并进行数据加载;

数据加载完成后,footerView消失,并将数据添加进RecyclerView;

用户再次下拉,重复上面的步骤。

这里有几点需要注意:

RecyclerView初次加载时,当item不满一页时,footerView应隐藏;

数据加载失败(网络错误等)时,footView应提示,并取消上拉加载事件,添加点击重新加载事件;

服务器数据全部加载完成后,footView也应提示,并取消上拉加载事件。

代码实现:

首先,我们定义RecyclerView的item和footerView:

item的xml布局:

android:orientation="vertical" android:layout_width="match_parent"

android:layout_height="48dp">

android:id="@+id/tv_item_test"

android:layout_width="match_parent"

android:layout_height="48dp"

android:text="测试数据1"

android:paddingLeft="16dp"

android:gravity="center_vertical|left"/>

footerView的xml布局:

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/load_layout"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:paddingBottom="12dip"

android:paddingTop="12dip"

android:orientation="vertical">

android:id="@+id/ll_footer_loading"

android:layout_width="match_parent"

android:layout_height="40dp"

android:gravity="center"

android:orientation="horizontal">

style="?android:attr/progressBarStyleSmall"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

android:id="@+id/more_data_msg"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="16dp"

android:text="正在加载..." />

android:id="@+id/ll_footer_error"

android:layout_width="match_parent"

android:layout_height="40dp"

android:gravity="center"

android:orientation="horizontal"

android:clickable="true">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="网络错误,点击重新加载" />

android:id="@+id/ll_footer_all_loaded"

android:layout_width="match_parent"

android:layout_height="40dp"

android:gravity="center"

android:orientation="horizontal">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="已经全部加载完啦!" />

嗯,看起来比较复杂,其实就是三个状态的布局,我们可以在代码中控制其显示、隐藏。

然后,我们来写RecyclerView的适配器。

首先,我们知道RecyclerView适配器中,有这个方法:

public int getItemViewType(int position) {

return 0;

}

利用这个方法,我们可以判断item是普通item还是底部的FooterView,我们定义两个类型:

/**

* 普通项和底部

*/

private final int TYPE_ITEM=1;

private final int TYPE_FOOTER=2;

然后,重写getItemViewType方法和getItemCount方法:

@Override

public int getItemViewType(int position) {

if(position+1==getItemCount()){ // 到了底部

return TYPE_FOOTER;

}else {

return TYPE_ITEM;

}

}

@Override

public int getItemCount() {

return mData.size()!=0?mData.size()+1:0;

}

然后,创建我们的ViewHolder,并且重写onCreateViewHolder方法,在这里,我们根据itemType,来决定要加载的布局:

private View mFootView;

class MyViewHolder extends RecyclerView.ViewHolder{

public TextView tvTest;

public LinearLayout llLoading; // 正在加载

public LinearLayout llLoadError; // 错误

public LinearLayout llLoadedAll; // 全部加载完

public MyViewHolder(View itemView) {

super(itemView);

// 判断是否是底部加载的view

if(mFootView==null || itemView!=mFootView){

tvTest=(TextView)itemView.findViewById(R.id.tv_item_test);

}

if(mFootView!=null && mFootView==itemView){

llLoading=(LinearLayout)itemView.findViewById(R.id.ll_footer_loading);

llLoadError=(LinearLayout)itemView.findViewById(R.id.ll_footer_error);

llLoadedAll=(LinearLayout)itemView.findViewById(R.id.ll_footer_all_loaded);

}

}

}

@Override

public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

if(viewType==TYPE_ITEM){

// 普通item

View view= LayoutInflater.from(mContext).inflate(R.layout.item_rv_test,parent,false);

return new MyViewHolder(view);

} else{

// 底部

mFootView=LayoutInflater.from(mContext).inflate(R.layout.item_first_footer,parent,false);

return new MyViewHolder(mFootView);

}

}

接下来是最重要的onBindViewHolder方法,在这里,我们首先根据itemType,判断ViewHolder数据,然后,判断footerView的状态:

/**

* 底部上拉加载的view有四种状态:

* 初始时:隐藏(避免recyclerView的item不满一页时,上拉加载的view一直显示)

* 第一次滑动后:显示(显示信息为正在加载)

* 网络错误时:显示(显示信息为网络错误,点击重新加载)

* 全部都已加载完时:显示(显示信息为已全部加载完毕)

*/

public static final int STATE_FIRST=1;

public static final int STATE_SHOW=2;

public static final int STATE_ERROR_NET=3;

public static final int STATE_ALL_LOADED=4;

/**

* 当前加载状态

*/

private int mLoadState=STATE_FIRST;

@Override

public void onBindViewHolder(MyViewHolder holder, int position) {

if(getItemViewType(position)==TYPE_ITEM){ // 普通项

holder.tvTest.setText(mData.get(position));

}else { // 底部

switch (mLoadState){ // 判断底部上拉加载的view的状态

case STATE_FIRST: // 初始状态 view为隐藏

mFootView.setVisibility(View.GONE);

holder.llLoading.setVisibility(View.VISIBLE);

holder.llLoadError.setVisibility(View.GONE);

holder.llLoadedAll.setVisibility(View.GONE);

break;

case STATE_SHOW:

mFootView.setVisibility(View.VISIBLE);

holder.llLoading.setVisibility(View.VISIBLE);

holder.llLoadError.setVisibility(View.GONE);

holder.llLoadedAll.setVisibility(View.GONE);

break;

case STATE_ERROR_NET:

mFootView.setVisibility(View.VISIBLE);

holder.llLoading.setVisibility(View.GONE);

holder.llLoadError.setVisibility(View.VISIBLE);

holder.llLoadedAll.setVisibility(View.GONE);

// 重新加载

if(mOnListener!=null){

holder.llLoadError.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

mOnListener.onReLoad();

}

});

}

break;

case STATE_ALL_LOADED:

mFootView.setVisibility(View.VISIBLE);

holder.llLoading.setVisibility(View.GONE);

holder.llLoadError.setVisibility(View.GONE);

holder.llLoadedAll.setVisibility(View.VISIBLE);

break;

}

}

}

private OnListener mOnListener;

// item点击事件和底部重新加载点击事件

public interface OnListener{

void onItemClick();

void onReLoad();

}

恩,主要代码就是这样,然后我们就可以在Activity中设置RecyclerView的点击事件、RecyclerView的滑动事件:

// recyclerView的item点击事件,和网络错误时重新加载的点击事件

mAdapter.setListener(new RvLoadMoreAdapter.OnListener() {

@Override

public void onItemClick() { // item点击事件

}

@Override

public void onReLoad() { // 重新加载

}

});

// 监听RecyclerView的滑动事件,判断是否是手指向上滑动,避免item不满一页时,下拉刷新触发上拉加载事件。

private boolean isUp=false;

mRv.setOnTouchListener(new View.OnTouchListener() {

float oldy;

@Override

public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()){

case MotionEvent.ACTION_DOWN:

oldy=event.getY();

break;

case MotionEvent.ACTION_UP:

if(oldy-event.getY()>ViewConfiguration.get(mContext).getScaledTouchSlop()){

isUp=true;

} else {

isUp=false;

}

}

return false; // 不拦截事件

}

});

mRv.addOnScrollListener(new RecyclerView.OnScrollListener() {

private int lastVisibleItemPosition;

@Override

public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

super.onScrollStateChanged(recyclerView, newState);

//正在滚动

if(isUp && !mAdapter.ismIsLoading() && newState==RecyclerView.SCROLL_STATE_IDLE &&

lastVisibleItemPosition+1==mAdapter.getItemCount()){ // 判断条件:手指上滑、当前不是正在加载的状态、停止滑动、末尾的item为最后一项

// 初始状态时,footer为隐藏,这里将其设为可见

mAdapter.showFooter();

if(mAdapter.getLoadState()==RvLoadMoreAdapter.STATE_FIRST){ //初始状态

mAdapter.setmLoadState(false,false,null);

}

// 只有显示状态时,才能响应滑动事件(不包括错误状态和加载完成状态)

if(mAdapter.getLoadState()==RvLoadMoreAdapter.STATE_SHOW){ // 显示状态

mAdapter.setmIsLoading(true);

// 这里写加载事件

}

}

}

@Override

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

super.onScrolled(recyclerView, dx, dy);

lastVisibleItemPosition=mLayoutManager.findLastVisibleItemPosition();

}

});

基本逻辑就是这样了,具体代码可以看demo,演示如下:

33d246af5904

image

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值