目录
3.4.PtrDefaultHandler实现了PtrHandler接口
7.数据加载完成通知PtrClassicFrameLayout刷新完成
PtrClassicFrameLayout开源git地址:https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh
支持最低版本API LEVEL >= 8
PtrClassicFrameLayout类关系图如下:
1.PtrClassicFrameLayout是什么?
下拉刷新,(android-Ultra-Pull-To-Refresh)是一个功能强大的下拉刷新控件,需要在自己的视图内部实现自己加载下一页的效果,简称(UltraPTR);
2.PtrClassicFrameLayout优点有哪些?
PtrClassicFrameLayout是旧的下拉刷新的替代方案,PtrClassicFrameLayout内部可以包含任意视图实现下拉刷新功能;PtrClassicFrameLayout是一个比Google提供SwipeRefreshLayout下拉刷新功能更加强大的控件;PtrClassicFrameLayout支持像ListView添加headview一样容易的自定义headview功能;
a.PtrClassicFrameLayout主要包含两部分视图mContent和mHeaderView
protected View mContent; //实际要显示的内容视图
private View mHeaderView; //下拉刷新的头部视图,可以自定义
b.可以自定义headView需要实现PtrUIHandler接口
public class CustomPtrHeader extends FrameLayout implements PtrUIHandler{}
PtrClassicFrameLayout主要实现了下拉刷新功能,未实现上拉加载更多效果,实际上上拉加载更多不是必要功能(例如 :支付宝的首页,航旅纵横首页等很多软件界面可能只需要下拉刷新,不需要上拉加载更多),下拉刷新几乎是每个APP必备功能;
3.PtrClassicFrameLayout关键类说明?
3.1.PtrFrameLayout
PtrFrameLayout继承ViewGroup,PtrFrameLayout完成视图的绘制(4.PtrClassicFrameLayout绘制流程?)和下拉刷新显示功能(5.触摸实现下拉刷新流程?);
3.2.PtrUIHandler
private PtrUIHandlerHolder mPtrUIHandlerHolder = PtrUIHandlerHolder.create();
private PtrHandler mPtrHandler;
PtrUIHandler是UI接口,自定headView时实现PtrUIHandler接口,根据下拉刷新状态执行相应状态到的回调改变headView显示状态,PtrUIHandler接口定义了四个方法;
//自定义headView实现的UI接口,根据headView状态调整headView视图显示或隐藏
public interface PtrUIHandler {
/**
*当视图已经到达顶部同时完成了刷新操作,可以做自定义headview视图恢复初始状态
* @param frame
*/
public void onUIReset(PtrFrameLayout frame);
/**
* 刷新准备,可以修改headview刷新视图样式
* @param frame
*/
public void onUIRefreshPrepare(PtrFrameLayout frame);
/**
* UI刷新开始,可以修改headview刷新视图样式
*/
public void onUIRefreshBegin(PtrFrameLayout frame);
/**
* 刷新完成以后,可以修改headview刷新视图样式
*/
public void onUIRefreshComplete(PtrFrameLayout frame);
//下拉时headView移动位置变化监听
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator);
}
3.3.PtrUIHandler
PtrHandler功能接口
/**
* 检查是否可以开始刷新;例如当content内容视图里面是空的或者第一个视图显示的时候
* <p/>
* {@link in.srain.cube.views.ptr.PtrDefaultHandler#checkContentCanBePulledDown}
*/
public boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header);
/**
* 刷新开始,回调提示执行刷新操作,在实现的回调方法执行刷新操作
*
* @param frame
*/
public void onRefreshBegin(final PtrFrameLayout frame);
3.4.PtrDefaultHandler实现了PtrHandler接口
实现了checkCanDoRefresh()方法,在checkCanDoRefresh()里面主要实现是否满足下拉刷新的条件;
需要自己执行设置监听刷新开始回调;
mPtrFrame.setPtrHandler(new PtrDefaultHandler() {
@Override
public void onRefreshBegin(PtrFrameLayout frame) {
//在此处执行刷新操作加载第一页数据
}
});
3.5.PtrUIHandlerHolder
PtrUIHandlerHolder包裹PtrUIHandler链表,优点是在PtrUIHandlerHolder包裹类在调用PtrUIHandler时做一些额外处理在执行回调方法;
class PtrUIHandlerHolder implements PtrUIHandler {
private PtrUIHandler mHandler;
private PtrUIHandlerHolder mNext;
}
当有刷新状态变化时会刷新链表下的所有回调,例如:
//循环链表执行回调
@Override
public void onUIRefreshBegin(PtrFrameLayout frame) {
PtrUIHandlerHolder current = this;
do {
final PtrUIHandler handler = current.getHandler();
if (null != handler) {
handler.onUIRefreshBegin(frame);
}
} while ((current = current.mNext) != null);
}
3.6.PtrUIHandlerHook
钩子任务类,实现了 Runnable 接口,可以理解为在原来的操作之间,插入了一段任务去执行。一个钩子任务只能执行一次,通过调用 takeOver
去执行。执行结束,用户需要调用 resume
方法,去恢复执行原来的操作。如果钩子任务已经执行过了,调用 takeOver
将会直接恢复执行原来的操作。可以通过 PtrFrameLayout 类的 setRefreshCompleteHook(PtrUIHandlerHook hook)
进行设置。当用户调用refreshComplete()
方法表示刷新结束以后,如果有 hook 存在,先执行 hook 的 takeOver
方法,执行结束,用户需要主动调用 hook 的 resume
方法,然后才会进行 Header 回弹到顶部的动作。
4.PtrClassicFrameLayout绘制流程?
PtrClassicFrameLayout视图绘制主要执行了三个回调方法onMeasure,onLayout,onFinishInflate;
4.1.onMeasure
测试视图尺寸,测量mContent和mHeaderView尺寸;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHeaderView != null) {
//测试孩子视图的尺寸,measureChildWithMargins减去了ViewGroup的padding和子View的margin 保证child最大可用空间
measureChildWithMargins(mHeaderView, widthMeasureSpec, 0, heightMeasureSpec, 0);
MarginLayoutParams lp = (MarginLayoutParams) mHeaderView.getLayoutParams();
//获取headerView视图的高度包含上线margin
mHeaderHeight = mHeaderView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
//记录headerView视图的高度
mPtrIndicator.setHeaderHeight(mHeaderHeight);
}
if (mContent != null) {
measureContentView(mContent, widthMeasureSpec, heightMeasureSpec);
}
}
//希望孩子视图的宽度和高度,父视图给子视图指定的宽度和高度
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
private void measureContentView(View child,
int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
getPaddingTop() + getPaddingBottom() + lp.topMargin, lp.height);
//测试孩子视图的尺寸,childHeightMeasureSpec和childWidthMeasureSpec减去了ViewGroup的padding和子View的m