PtrClassicFrameLayout 下拉刷新控件源码分析

本文深入分析了PtrClassicFrameLayout的源码,包括其关键类如PtrFrameLayout、PtrUIHandler和PtrDefaultHandler的工作原理,以及下拉刷新的触摸事件处理和绘制流程。PtrClassicFrameLayout是一个强大的下拉刷新控件,支持自定义HeadView,并提供了自动刷新功能。文章还介绍了如何在数据加载完成后通知控件刷新完成。
摘要由CSDN通过智能技术生成

目录

1.PtrClassicFrameLayout是什么?

2.PtrClassicFrameLayout优点有哪些?

3.PtrClassicFrameLayout关键类说明?

3.1.PtrFrameLayout

3.2.PtrUIHandler

3.3.PtrUIHandler

3.4.PtrDefaultHandler实现了PtrHandler接口

3.5.PtrUIHandlerHolder

3.6.PtrUIHandlerHook

4.PtrClassicFrameLayout绘制流程?

4.1.onMeasure

4.2.onLayout

4.3.onFinishInflate

5.触摸实现下拉刷新流程?

5.1.按下事件

5.2.滑动事件

5.3.抬起事件

6.自动刷新实现

7.数据加载完成通知PtrClassicFrameLayout刷新完成

8.PtrClassicFrameLayout相关参数说明

9.自定义HeadView


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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值