Android下拉刷新和上拉加载更多
下拉刷新
通过android系统提供的组件:SwipeRefreshLayout
一、基本使用
1 xml中 添加 SwipeRefreshLayout 组件
该组件包含着要操作下拉刷新的控件 如ListView RecyclerView 等
注意这里的SwipeRefreshLayout组件的子布局只能有一个
<android.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"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</android.support.v7.widget.RecyclerView>
</android.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为1
currentPage = 1;
// 网络请求
askForOKHttp(sortWay);
loadingMore()监听方法:
private void loadingMore(){
// 实现上拉加载重要步骤,设置滑动监听器,RecyclerView自带的ScrollListener
mRecyclerView.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<String> array0,
ArrayList<String> array1,ArrayList<String> array2,
ArrayList<String> array3,boolean mHasMore) {
this.arrayList0 = array0;
this.arrayList5 = array1;
this.arrayList2 = array2;
this.arrayList3 = array3;
hasMore = mHasMore;
notifyDataSetChanged();
}
onCreateViewHolder 中: 设置不同的viewHolder (分数据item和底部foot item)
@Override
public 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"
>
<ImageView
android:id="@+id/imageView0"
android:layout_width="match_parent"
android:layout_height="50dp"
/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.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
也可以自己设置为自定义的 组件
如上方的
<ImageView
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));