使用android-Ultra-Pull-To-Refresh实

2018-05-30  本文已影响0人  flycode

官方地址

https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh

简单使用

PtrClassicDefaultHeader header = new PtrClassicDefaultHeader(this);        
ptrFrameLayout.addPtrUIHandler(header);
ptrFrameLayout.setHeaderView(header);
ptrFrameLayout.setPtrHandler(new PtrDefaultHandler() {
      @Override
      public void onRefreshBegin(PtrFrameLayout frame) {
          refresh();
      }
 });

PtrUIHandler接口

它的实现类为PtrClassicDefaultHeader、MaterialHeader、StoreHouseHeader、PtrUIHandlerHolder。

1、前三者为下拉刷新不同样式的实现类,可通过此接口自定义下拉刷新样式,接口方法如下:

public void onUIRefreshPrepare(PtrFrameLayout frame);
public void onUIRefreshBegin(PtrFrameLayout frame);
public void onUIRefreshComplete(PtrFrameLayout frame);
public void onUIReset(PtrFrameLayout frame);
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator);

2、PtrUIHandlerHolder是PtrUIHandler的持有者。内置静态方法addHandler、removeHandler,用于添加和移除PtrUIHandler。一个PtrUIHandlerHolder对象可以看作是链表结构的一个节点,在实现PtrUIHandler上述5个方法时,遍历所有的链表节点,调用对应的接口方法。

PtrFrameLayout

自定义属性
// 头部
<attr name="ptr_header" format="reference" />
// 内容
<attr name="ptr_content" format="reference" />
// 阻尼系数,默认1.7f,越大感觉下拉时越吃力
<attr name="ptr_resistance" format="float" />
// 触发刷新时移动的位置比例,默认1.2f,移动达到头部高度1.2倍时可触发刷新操作
<attr name="ptr_ratio_of_header_height_to_refresh" format="float" />
// 回弹延时,默认 200ms,回弹到刷新高度所用时间
<attr name="ptr_duration_to_close" format="integer" />

// 头部回弹时间,默认1000ms
<attr name="ptr_duration_to_close_header" format="integer" />
// 下拉刷新/释放刷新,默认释放刷新
<attr name="ptr_pull_to_fresh" format="boolean" />
// 刷新时保持头部,默认true
<attr name="ptr_keep_header_when_refresh" format="boolean" />
onMeasure方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    // 测量headerView的宽高
    if (mHeaderView != null) {
        measureChildWithMargins(mHeaderView, widthMeasureSpec, 0, heightMeasureSpec, 0);
        MarginLayoutParams lp = (MarginLayoutParams) mHeaderView.getLayoutParams();
        mHeaderHeight = mHeaderView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
        mPtrIndicator.setHeaderHeight(mHeaderHeight);
    }
    // 对ContentView进行测量
    if (mContent != null) {
        measureContentView(mContent, widthMeasureSpec, heightMeasureSpec);
    }
}

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);
    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

调用measureChildWithMargins方法对HeaderView进行测量,获得headerView高度
调用getChildMeasureSpec(int spec, int padding, int childDimension)获得子View的MeasureSpec,调用child.measure(childWidthMeasureSpec, childHeightMeasureSpec),对ContentView进行测量

onLayout方法
protected void onLayout(boolean flag, int i, int j, int k, int l) {
    layoutChildren();
}

private void layoutChildren() {
    int offset = mPtrIndicator.getCurrentPosY();
    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    // 对HeaderView进行layout,主要是top的计算
    if (mHeaderView != null) {
        MarginLayoutParams lp = (MarginLayoutParams) mHeaderView.getLayoutParams();
        final int left = paddingLeft + lp.leftMargin;
        // enhance readability(header is layout above screen when first init)
        final int top = -(mHeaderHeight - paddingTop - lp.topMargin - offset);
        final int right = left + mHeaderView.getMeasuredWidth();
        final int bottom = top + mHeaderView.getMeasuredHeight();
        mHeaderView.layout(left, top, right, bottom);
    }
    // 对ContentView进行layout
    if (mContent != null) {
        if (isPinContent()) {
            offset = 0;
        }
        MarginLayoutParams lp = (MarginLayoutParams) mContent.getLayoutParams();
        final int left = paddingLeft + lp.leftMargin;
        final int top = paddingTop + lp.topMargin + offset;
        final int right = left + mContent.getMeasuredWidth();
        final int bottom = top + mContent.getMeasuredHeight();
        mContent.layout(left, top, right, bottom);
    }
}
dispatchTouchEvent方法
public boolean dispatchTouchEvent(MotionEvent e) {
    if (!isEnabled() || mContent == null || mHeaderView == null) {
        return dispatchTouchEventSupper(e);
    }
    int action = e.getAction();
    switch (action) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            mPtrIndicator.onRelease();
            if (mPtrIndicator.hasLeftStartPosition()) {
                // 松手的位置大于初始位置
                onRelease(false);
                if (mPtrIndicator.hasMovedAfterPressedDown()) {
                    sendCancelEvent();
                    return true;
                }
                return dispatchTouchEventSupper(e);
            } else {
                return dispatchTouchEventSupper(e);
            }

        case MotionEvent.ACTION_DOWN:
            mHasSendCancelEvent = false;
            // 记录按下的位置
            mPtrIndicator.onPressDown(e.getX(), e.getY());
            mScrollChecker.abortIfWorking();
            // 重置水平方向阻止标记
            mPreventForHorizontal = false;
            // The cancel event will be sent once the position is moved.
            // So let the event pass to children.
            // fix #93, #102
            dispatchTouchEventSupper(e);
            return true;
            
        case MotionEvent.ACTION_MOVE:
            mLastMoveEvent = e;
            mPtrIndicator.onMove(e.getX(), e.getY());
            // 相对上次位置偏移量(阻尼系数转化后)
            float offsetX = mPtrIndicator.getOffsetX();
            float offsetY = mPtrIndicator.getOffsetY();
            // 水平方向移动较大,事件可以继续分发下去
            if (mDisableWhenHorizontalMove && !mPreventForHorizontal && (Math.abs(offsetX) > mPagingTouchSlop && Math.abs(offsetX) > Math.abs(offsetY))) {
                if (mPtrIndicator.isInStartPosition()) {
                    mPreventForHorizontal = true;
                }
            }
            if (mPreventForHorizontal) {
                return dispatchTouchEventSupper(e);
            }
            boolean moveDown = offsetY > 0;
            boolean moveUp = !moveDown;
            boolean canMoveUp = mPtrIndicator.hasLeftStartPosition();
            // disable move when header not reach top
            if (moveDown && mPtrHandler != null && !mPtrHandler.checkCanDoRefresh(this, mContent, mHeaderView)) {
                return dispatchTouchEventSupper(e);
            }
            if ((moveUp && canMoveUp) || moveDown) {
                movePos(offsetY);
                return true;
            }
    }
    return dispatchTouchEventSupper(e);
}
位置更新方法
private void updatePos(int change) {
    if (change == 0) {
        return;
    }
    boolean isUnderTouch = mPtrIndicator.isUnderTouch();
    // once moved, cancel event will be sent to child
    if (isUnderTouch && !mHasSendCancelEvent && mPtrIndicator.hasMovedAfterPressedDown()) {
        mHasSendCancelEvent = true;
        sendCancelEvent();
    }
    // leave initiated position or just refresh complete
    if ((mPtrIndicator.hasJustLeftStartPosition() && mStatus == PTR_STATUS_INIT) ||
            (mPtrIndicator.goDownCrossFinishPosition() && mStatus == PTR_STATUS_COMPLETE && isEnabledNextPtrAtOnce())) {
        mStatus = PTR_STATUS_PREPARE;
        mPtrUIHandlerHolder.onUIRefreshPrepare(this);
    }
    // back to initiated position
    if (mPtrIndicator.hasJustBackToStartPosition()) {
        tryToNotifyReset();
        // recover event to children
        if (isUnderTouch) {
            sendDownEvent();
        }
    }
    // Pull to Refresh
    if (mStatus == PTR_STATUS_PREPARE) {
        // reach fresh height while moving from top to bottom
        if (isUnderTouch && !isAutoRefresh() && mPullToRefresh
                && mPtrIndicator.crossRefreshLineFromTopToBottom()) {
            tryToPerformRefresh();
        }
        // reach header height while auto refresh
        if (performAutoRefreshButLater() && mPtrIndicator.hasJustReachedHeaderHeightFromTopToBottom()) {
            tryToPerformRefresh();
        }
    }
    // 核心移动方法
    mHeaderView.offsetTopAndBottom(change);
    if (!isPinContent()) {
        mContent.offsetTopAndBottom(change);
    }
    invalidate();
    if (mPtrUIHandlerHolder.hasHandler()) {
        mPtrUIHandlerHolder.onUIPositionChange(this, isUnderTouch, mStatus, mPtrIndicator);
    }
    onPositionChange(isUnderTouch, mStatus, mPtrIndicator);
}
上一篇下一篇

猜你喜欢

热点阅读