Android下拉刷新和上拉加载更多
Android下拉刷新和上拉加载更多
下拉刷新
通过android系统提供的组件:SwipeRefreshLayout
一、基本使用
1 xml中 添加 SwipeRefreshLayout 组件
该组件包含着要操作下拉刷新的控件 如ListView RecyclerView 等
注意这里的SwipeRefreshLayout组件的子布局只能有一个
.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_below="@+id/dividerimage0" android:layout_width="match_parent" android:layout_height="match_parent" > .support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" > .support.v7.widget.RecyclerView> .support.v4.widget.SwipeRefreshLayout>
2 java代码中初始化
private SwipeRefreshLayout swipeRefreshLayout;swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
3 设置刷新时的颜色变化
swipeRefreshLayout.setColorSchemeResources( R.color.colorPrimary, R.color.green, R.color.red );
4 所在Activity类也要implements SwipeRefreshLayout.OnRefreshListener
5 重写下拉刷新方法
@Override public void onRefresh() { // 网络请求 okHttp.getHandler(handlerForGenJin); // 这里用sortWay变量 这样即使下拉刷新也能保持用户希望的排序方式 askForOkHttp(sortWay); }
6 当网络请求完 获取并解析了数据,通知结束下拉刷新
// 通知结束下拉刷新 handlerForRefresh.sendEmptyMessage(0x93);
7
Handler handlerForRefresh = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0x93: { swipeRefreshLayout.setRefreshing(false); } } } };
8 开启监听
onCreate()中
swipeRefreshLayout.setOnRefreshListener(this);
问题:当下拉刷新后,会发现Item之间的间距增大,刷新一次增大一次
分析:因为你每次调用initView ,这样每次都会执行
mRecyclerView.addItemDecoration(new MyDividerItemDecoration( this, DividerItemDecoration.VERTICAL));
也就是每次都会加一次分隔线,因此要设置一个boolean变量的值,判断是否是第一次加载界面,是的话就加分隔线,否则就不加分隔线了
if (IsFirstOnCreate) { mRecyclerView.addItemDecoration(new MyDividerItemDecoration( this, DividerItemDecoration.VERTICAL)); IsFirstOnCreate = false; }
从别的界面回传通知本界面执行下拉刷新
通过 intent 的 startActivityForResult方式去跳转 设置请求码回传码
在onActivityResult中:
@Override public void onActivityResult(int requestCode,int resultCode,Intent data){ super.onActivityResult(requestCode,resultCode,data); if(requestCode==0x05){ if(resultCode==0x05){ swipeRefreshLayout.setOnRefreshListener(this); swipeRefreshLayout.post(new Runnable() { @Override public void run() { swipeRefreshLayout.setRefreshing(true); } }); this.onRefresh(); } } }
上拉加载更多
主要是利用RecyclerView自带的ScrollListener去监听是否滑动到了底部
设置底部的Item样式
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/foot_tips" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="15sp" android:padding="10dp" android:layout_marginBottom="1dp"/>LinearLayout>
Activity中
private LinearLayoutManager mLayoutManager; private static boolean hasMore = false; // 是否有下一页 private static int currentPage ; // 若是上拉加载更多的网络请求 则不需要删除数据 private boolean isLoadingMore = false; // 最后一个条目位置 private static int lastVisibleItem = 0;
oncreate中
loadingMore();// 初始currentPage为1currentPage = 1;// 网络请求askForOKHttp(sortWay);
loadingMore()监听方法:
private void loadingMore(){// 实现上拉加载重要步骤,设置滑动监听器,RecyclerView自带的ScrollListenermRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if(!isLoadingMore){ // 若不是加载更多 才 加载 // 在newState为滑到底部时 if (newState == RecyclerView.SCROLL_STATE_IDLE) { // 如果没有隐藏footView,那么最后一个条目的位置(带数据)就比我们的getItemCount少1 if (!mAdapter.isFadeTips() && lastVisibleItem + 1 == mAdapter.getItemCount()) { // 然后调用updateRecyclerview方法更新RecyclerView updateRecyclerView(); } // 如果隐藏了提示条,我们又上拉加载时,那么最后一个条目(带数据)就要比getItemCount要少2 if (mAdapter.isFadeTips() && lastVisibleItem + 2 == mAdapter.getItemCount()) { // 然后调用updateRecyclerview方法更新RecyclerView updateRecyclerView(); // 要调 } } } } //滚动监听 @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // 在滑动完成后,拿到最后一个可见的item的位置 lastVisibleItem = mLayoutManager.findLastVisibleItemPosition(); }});
mLayoutManager要为 LinearLayoutManager 类型的
// 上拉加载时调用的更新RecyclerView的方法 private void updateRecyclerView() { if(hasMore){ // 还有下一页 网络请求 第二页 第三页 currentPage++; // 加1 isLoadingMore = true; askForOKHttp(sortWay); }
Adapter中:
声明:
private int normalType = 0; // 第一种ViewType,正常的item private int footType = 1; // 第二种ViewType,底部的提示View private static boolean hasMore = true; // 变量,是否有更多数据 private boolean fadeTips = false; // 变量,是否隐藏了底部的提示
构造方法的形参 除了传入数据,增加一个hasMore变量 用于判断是否有更多
更新数据也是
/** * 更新数据 */ public void updateData(ArrayList array0, ArrayList array1,ArrayList array2, ArrayList array3,boolean mHasMore) { this.arrayList0 = array0; this.arrayList5 = array1; this.arrayList2 = array2; this.arrayList3 = array3; hasMore = mHasMore; notifyDataSetChanged(); }
onCreateViewHolder 中: 设置不同的viewHolder (分数据item和底部foot item)
@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == normalType) { ViewHolder viewHolder = null; // 实例化展示的view View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_choose_customer, parent, false); // 实例化viewholder viewHolder = new ViewHolder(v, mItemClickListener); return viewHolder; }else { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_foot_layout, parent, false); FootHolder footHolder = new FootHolder(v); return footHolder; }}
onBindViewHolder中:
@Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) { // 如果是正常的imte,直接设置TextView的值 if (holder instanceof ViewHolder) { ((ViewHolder) holder).customerName.setText(arrayList0.get(position)); ((ViewHolder) holder).qiangduo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mItemInnerDeleteListener.onItemInnerDeleteClick(position); } }); }else { if (hasMore) { // 不隐藏footView提示 fadeTips = false; if (arrayList0.size() > 0) { // 如果查询数据发现增加之后,就显示正在加载更多 ((FootHolder) holder).tips.setVisibility(View.VISIBLE); ((FootHolder) holder).tips.setText("正在加载更多..."); } } else { if (arrayList0.size() > 0) { // 如果查询数据发现并没有增加时,就显示没有更多数据了 ((FootHolder) holder).tips.setText("暂无更多数据"); // 然后通过主线程延时让这个提示消失,在1000ms后执行 mHandler.postDelayed(new Runnable() { @Override public void run() { // 隐藏提示条 ((FootHolder) holder).tips.setVisibility(View.GONE); // 将fadeTips设置true fadeTips = true; // hasMore设为true是为了让再次拉到底时,会先显示正在加载更多 hasMore = true; } }, 1000); } } } }
@Override public int getItemCount() { // 获取item的数量 计上footView return arrayList0 == null ? 0 : arrayList0.size()+1; } // 自定义方法,获取数据的最后一个位置,不计上footView public int getRealLastPosition() { return arrayList0.size(); }
// 根据条目位置返回ViewType,以供onCreateViewHolder方法内获取不同的Holder @Override public int getItemViewType(int position) { if (position == getItemCount() - 1) { return footType; } else { return normalType; } }
// 暴露接口,改变fadeTips的方法 public boolean isFadeTips() { return fadeTips; }
// 正常item的ViewHolder,用以缓存findView操作 class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ TextView XXX XXX XXX ; private MyItemClickListener mListener; ... ... }
// 底部footView的ViewHolder,用以缓存findView操作 class FootHolder extends RecyclerView.ViewHolder { private TextView tips; FootHolder(View itemView) { super(itemView); tips = itemView.findViewById(R.id.foot_tips); } }
也可以使用第三方库实现上拉加载 下拉刷新
参考:https://github.com/scwang90/SmartRefreshLayout
上部和下部的会隐藏 然后下拉或者上拉 都会显示 然后过一定时间又会收回
和RecyclerView结合,则会有默认的一个 刷新样式
包括RecyclerView和其他组件,recyclerView控件上方/下方的组件 会作为 刷新的控件,设置控件的动画样式即为刷新或者加载的动画样式
只能设置3个子View 否则报错
Caused by: java.lang.RuntimeException: 最多只支持3个子View,Most only support three sub view
如:
<com.scwang.smartrefresh.layout.SmartRefreshLayout android:id="@+id/smartRefresh" android:layout_width="match_parent" android:layout_height="match_parent" > "@+id/imageView0" android:layout_width="match_parent" android:layout_height="50dp" /> .support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent"> .support.v7.widget.RecyclerView> <com.scwang.smartrefresh.layout.footer.BallPulseFooter android:layout_width="match_parent" android:layout_height="50dp"/> com.scwang.smartrefresh.layout.SmartRefreshLayout>
待处理:限制下拉和上拉加载的高度限制
有三种添加的方式:
1 在 App extends Application的类中
static静态代码块中
优先级最低
2 在XML中
<com.scwang.smartrefresh.layout.SmartRefreshLayout android:layout_width="match_parent" android:layout_height="match_parent" >
使用 提供的 一些 好看的效果
如上方的
<com.scwang.smartrefresh.layout.footer.BallPulseFooter
也可以自己设置为自定义的 组件
如上方的
java中开启帧动画
ImageView imageView = findViewById(R.id.imageView0); imageView.setImageResource(R.drawable.run_animation_list); AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable(); animationDrawable.start();
3 java代码设置
final RefreshLayout refreshLayout = (RefreshLayout) findViewById(R.id.refreshLayout);//设置 Header 为 贝塞尔雷达 样式refreshLayout.setRefreshHeader(new BezierRadarHeader(this).setEnableHorizontalDrag(true));//设置 Footer 为 球脉冲 样式refreshLayout.setRefreshFooter(new BallPulseFooter(this).setSpinnerStyle(SpinnerStyle.Scale));
更多相关文章
- 实现Android(安卓)ListView 自动加载更多内容
- Android四种Activity的加载模式
- Android开发实践 带你理解使用WebView
- Android高效加载大图、多图解决方案,有效避免程序OOM
- android 自定义Dialog(背景图等)
- michael / afinal
- Android实现系统下拉栏的消息提示——Notification
- Android(安卓)studio 下拉刷新,加载更多使用LoadingViewFinal
- Android(安卓)关于WebView加载完成的多种监听方式