以前一直想写一个自己用的下拉插件,最近自己也看了很多的下拉插件。所以总结了一下,自己写了一个下拉刷新插件。实现的这个下拉刷新的框架,并不是自己的原创,在完成过程中是参考了很多开源的框架,并把自己认为比较好的东西借鉴了过来,从而形成我的东西。
实现原理
1、LoadingLayout是实现刷新头部和尾部布局的主要文件,而CustomLayout则继承自LoadingLayout的抽象类,它定义了一些自定义方法。在LoadingLayout中声明了刷新文字、时间、图片等设置和状态的改变方法。
【1】Header
Headr布局文件主要是实现下拉动画实现,据下拉的距离来改变它的状态,从而显示不同的样式。
【2】Footer
Footer布局文件是自动加载更多等状态显示已经上拉刷新状态改变,从而显示不停的样式。
2、PullRefreshBase是这个刷新框架最重要的基本组件。它是一个继承LinearLayout的抽象类,主要是实现了刷新视图T与Header和Footer以及手势滑动、状态改变的处理逻辑。由于传入的是泛型T,所以它可以支持多种刷新组件的组合。比如LinearLayout、GridView、WebView、RecycleView等,同时也可以传入自己的自定义视图来实现。
【1】OnRefreshListener刷新接口监听。
/**
* 下拉松手后调用
*
* @param refreshView 刷新的view
*/
void onPullDownRefresh(final PullRefreshBase<V> refreshView);
/**
* 加载更多或上拉时调用
*
* @param refreshView 刷新的view
*/
void onPullUpToRefresh(final PullRefreshBase<V> refreshView);
【2】通过对onInterceptTouchEvent方法重写,来对Touch进行拦截来判断滑动手势的操作。同时再根据是否拦截判断是否要传递给子视图。而onTouchEvent方法则根据拦截操作的标识来判断是否消费事件,不然就传递给父视图操作。
/**
* Touch事件拦截器
*
* @param event
* @return
*/
@Override
public final boolean onInterceptTouchEvent(MotionEvent event) {
if (!isInterceptTouchEventEnabled()) {
return false;
}
if (!isPullLoadEnabled() && !isPullRefreshEnabled()) {
return false;
}
final int action = event.getAction();
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mIsHandledTouchEvent = false;
return false;
}
if (action != MotionEvent.ACTION_DOWN && mIsHandledTouchEvent) {
return true;
}
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastMotionY = event.getY();
mIsHandledTouchEvent = false;
break;
case MotionEvent.ACTION_MOVE:
final float deltaY = event.getY() - mLastMotionY;
final float absDiff = Math.abs(deltaY);
// 这里有三个条件:
// 1,位移差大于mTouchSlop,这是为了防止快速拖动引发刷新
// 2,isPullRefreshing(),如果当前正在下拉刷新的话,是允许向上滑动,并把刷新的HeaderView挤上去
// 3,isPullLoading(),理由与第2条相同
if (absDiff > mTouchSlop || isPullRefreshing() || isPullLoading()) {
mLastMotionY = event.getY();
// 第一个显示出来,Header已经显示或拉下
if (isPullRefreshEnabled() && isReadyForPullDown()) {
// 1,Math.abs(getScrollY()) > 0:表示当前滑动的偏移量的绝对值大于0,表示当前HeaderView滑出来了或完全
// 不可见,存在这样一种case,当正在刷新时并且RefreshableView已经滑到顶部,向上滑动,那么我们期望的结果是
// 依然能向上滑动,直到HeaderView完全不可见
// 2,deltaY > 0.5f:表示下拉的值大于0.5f
mIsHandledTouchEvent = (Math.abs(getScrollYValue()) > 0 || deltaY > 0.5f);
// 如果截断事件,我们则仍然把这个事件交给刷新View去处理,典型的情况是让ListView/GridView将按下
// Child的Selector隐藏
if (mIsHandledTouchEvent) {
mRefreshableView.onTouchEvent(event);
}
} else if (isPullLoadEnabled() && isReadyForPullUp()) {
// 原理如上
mIsHandledTouchEvent = (Math.abs(getScrollYValue()) > 0 || deltaY < -0.5f);
}
}
break;
default:
break;
}
return mIsHandledTouchEvent;
}
3、总体布局视图
基本组件
1、框架内置提供PullRefreshRecyclerview,PullRefreshListView,PullRefreshWebView这三种刷新组件。PullRefreshRecyclerview最强大,它可以实现LinearView和GridView。而之所以提供PullRefreshListView,是主要供自定义的ListView和adapter来实现速度更快和多种样式的ListView。
【1】PullRefreshRecyclerview是一个自定义的下拉刷新RecyclerView扩展。我们知道RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能。可以支持GridView与ListView,它的功能更加强大。
这里主要参考了HeaderAndFooterRecyclerView和LRecyclerView。
RecyclerAdapter:这个adapter是继承RecyclerView.Adapter的抽象类。主要封装了实现Header、Footer和Contents之间逻辑处理的关系。主要包括:
/**
* 点击事件接口
*/
public interface OnItemClickLitener {
void onItemClick(View view, int position);
boolean onItemLongClick(View view, int position);
}
void addHeaderView(View header)
void addFooterView(View footer)
int getCount()
/**
*数据处理逻辑
*/
void add(D object)
void addAll(Collection<? extends D> collection)
void addAll(D[] items)
void insert(D object, int index)
void insertAll(D[] object, int index)
void insertAll(Collection<? extends D> object, int index)
void remove(D object)
void remove(int position)
void clear()
void sort(Comparator<? super D> comparator)
/**
* 创建视图,交给子类实现方法
*
* @param parent
* @param viewType
* @return
*/
public abstract BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType);
BaseViewHolder:这个ViewHolder是继承RecyclerView.ViewHolder的抽象类,主要是将视图处理与adapter的逻辑处理分离开来了。因此更加便于处理和操作。在建立adapter时就会要求生成BaseViewHolder。
以上RecyclerAdapter和BaseViewHolder主要参考了EasyRecyclerView
【2】PullRefreshListView是一个自定义的下拉刷新ListView扩展。之所以保留是为了更加方便的自定义和使用自己定义的adapter。
【3】PullRefreshWebView是一个自定义的下拉刷新WebView扩展。只支持下拉刷新。
2、框架内包括了几种常用的基本刷新样式,Headr样式主要包括:DefaultHeaderLoadingLayout、IndicatorViewHeaderLoadingLayout、ProgressBarHeaderLoadingLayout、RotateHeaderLoadingLayout这几种,当然你可以自定义自己的样式。Footer样式主要括:DefaultFooterLoadingLayout、IndicatorViewFooterLoadingLayout。
【1】header样式是继承CustomLoadingLayout,主要是覆盖某些必要的方法,如果要自定义可以参考DefaultHeaderLoadingLayout的样式和布局来操作。footer样式和header样式是一样的继承CustomLoadingLayout,只是处理的逻辑和显示的文字少一些。
【2】样式截图:
a、hader样式:
DefaultHeaderLoadingLayout:
IndicatorViewHeaderLoadingLayout:
ProgressBarHeaderLoadingLayout:
RotateHeaderLoadingLayout:
b、footer样式:
DefaultFooterLoadingLayout:
IndicatorViewFooterLoadingLayout:
具体用法请看demo