最近项目中由于统一使用SwipeRefreshLayout的下拉刷新,由于谷歌官方的SwipeRefreshLayout并没有提供上拉加载更多的功能,只好自己写一个,记一下以后可以直接拿出来用。
其实实现原理很中规中矩,无非就是给ListView添加一个脚布局(用于显示正在加载更多的提示),首先是隐藏的(设置一个负值padding,刚好为脚布局高度的相反数),当监听到用户滑倒最底端(当前可见的最后一个item是当前列表的最后一项再继续上拉的动作时显示脚布局,加载完成后再隐藏它,这里为了避免加载多次,我们需要记录用户上拉时是否正在加载,只有当同时满足:①没有正在加载;②当前已经到了最低端;③用户正在上拉操作时才加载更多。
这里我觉得重写onTouchEvent判断用户上拉还是下拉比较麻烦,就直接监听滑动状态,如果当前最后一个可见的item是列表最后一项,当滑动状态处于SCROLL_STATE_FLING(开始滚动)或者SCROLL_STATE_IDLE(处于空闲,已经停止)时,如果滑动状态再发生改变只能是变为SCROLL_STATE_TOUCH_SCROLL(滚动状态),由于最后一个可见的item必须是最后一个,所以综上可知只能变为向上拉(向下拉最后一个可见的就不是列表的最后一项了),下面是实现的代码
package com.meskal.customview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import com.meskal.R;
public class PullUpLoadMoreListView extends ListView implements AbsListView.OnScrollListener {
private boolean isLoading = false;
private View mFooterView;
private int mFooterHeight;
private OnLoadMoreListener mListener;
private LayoutInflater inflater;
public PullUpLoadMoreListView(Context context) {
this(context, null);
}
public PullUpLoadMoreListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PullUpLoadMoreListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
initFooterView();
setOnScrollListener(this);
}
/**
* 初始化脚布局
*/
private void initFooterView() {
mFooterView = inflater.inflate(R.layout.refresh_load_more, null);
mFooterView.measure(0, 0);
mFooterHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterHeight, 0, 0);
this.addFooterView(mFooterView);
}
@Override public void onScrollStateChanged(AbsListView absListView, int scrollstate) {
if(this.getLastVisiblePosition() == this.getAdapter().getCount() - 1
&& !isLoading && (scrollstate == SCROLL_STATE_FLING || scrollstate == SCROLL_STATE_IDLE)){
setLoadState(true);
if(this.mListener != null){
this.mListener.loadMore();
}
}
}
/**
* 设置状态
* @param b
*/
public void setLoadState(boolean b) {
this.isLoading = b;
if(isLoading){
mFooterView.setPadding(0,0,0,0);
this.setSelection(this.getAdapter().getCount() + 1);
}else {
mFooterView.setPadding(0,-mFooterHeight,0,0);
}
}
@Override public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
public void setOnLoadMoreListener(OnLoadMoreListener listener){
this.mListener = listener;
}
public interface OnLoadMoreListener{
void loadMore();
}
}
脚布局就很简单了,当然也可以更具需要定制更绚丽的进度提醒:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/block_bg"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:gravity="center"
>
<ProgressBar
android:id="@+id/progressBar"
style="@android:style/Widget.Holo.ProgressBar.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:textColor="#FF333333"
android:text="正在加载更多数据..."
/>
</LinearLayout>
</LinearLayout>
这里脚布局加了一个边框(drawable下添加一个block_bg.xml):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#fff"/>
<stroke
android:color="#d4d4d4"
android:width="1px"/>
</shape>
对外我们对外公开一个设置监听器和设置加载状态的方法,监听器接口在使用时实现这个接口去做加载更多的操作,设置正在加载中由控件本身负责,这个时候我们让脚布局显示出来,加载完成我们设置正在加载中(isLoading )为false就会隐藏脚布局,这里对于脚布局我们需要注意的时获取高度之前要先主动的去测量一下( mFooterView.measure(0, 0);),因为在view绘制中只有当view执行过onMeasure后才能得到具体宽高,否则得到的始终为0。
到这里,这个控件差不多写完了,其实配合SwipeRefreshLayout效果还不错。当然下拉刷新上拉加载的类库也有很多,像有名的PullToRefresh,功能十分强大,使用也很方便。还有记得之前使用过一个MaterialRefreshLayout,这个是比SwipeRefreshLayout更强大的刷新控件,支持上拉加载更多,上拉和下拉显示的都是转圈的动画,上拉在底部显示,而且支持动画显示是否是侵入式的覆盖在内容上方