android SwipeRefreshLayout 源码分析之 弹力计算分析。

打开源码发现 swipe 继承viewgruop ,通过NestedScrollingParent  和NestedScrollingChild辅助类来帮助头部的 下拉刷新滑动,

关于这个网上很多资料,在这里就不多解释,直接看   onTouchEvent 方法,swipe是在这里进行了下拉刷新的实现,在

onmove监听里发现这些代码:

case MotionEvent.ACTION_MOVE: {
    pointerIndex = ev.findPointerIndex(mActivePointerId);
    if (pointerIndex < 0) {
        Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
        return false;
    }

    final float y = ev.getY(pointerIndex);
    startDragging(y);

    if (mIsBeingDragged) {
        final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
        if (overscrollTop > 0) {
            moveSpinner(overscrollTop);
        } else {
            return false;
        }
    }
    break;
}

先打开 startDragging  发现是这样的,仅仅是标记开始滑动,

private void startDragging(float y) {
    final float yDiff = y - mInitialDownY;
    if (yDiff > mTouchSlop && !mIsBeingDragged) {
        mInitialMotionY = mInitialDownY + mTouchSlop;
        mIsBeingDragged = true;
        mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
    }
}

接着往下看 发现了 moveSpinner 方法,点开发现

private void moveSpinner(float overscrollTop) {
    mProgress.setArrowEnabled(true);
    float originalDragPercent = overscrollTop / mTotalDragDistance;

    float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
    float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
    float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;
    float slingshotDist = mUsingCustomStart ? mSpinnerOffsetEnd - mOriginalOffsetTop : mSpinnerOffsetEnd;
    float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2)
            / slingshotDist);
    float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(
            (tensionSlingshotPercent / 4), 2)) * 2f;
    float extraMove = (slingshotDist) * tensionPercent * 2;

    int targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove);
    // where 1.0f is a full circle
    if (mCircleView.getVisibility() != View.VISIBLE) {
        mCircleView.setVisibility(View.VISIBLE);
    }
    if (!mScale) {
        mCircleView.setScaleX(1f);
        mCircleView.setScaleY(1f);
    }

    if (mScale) {
        setAnimationProgress(Math.min(1f, overscrollTop / mTotalDragDistance));
    }
    if (overscrollTop < mTotalDragDistance) {
        if (mProgress.getAlpha() > STARTING_PROGRESS_ALPHA
                && !isAnimationRunning(mAlphaStartAnimation)) {
            // Animate the alpha
            startProgressAlphaStartAnimation();
        }
    } else {
        if (mProgress.getAlpha() < MAX_ALPHA && !isAnimationRunning(mAlphaMaxAnimation)) {
            // Animate the alpha
            startProgressAlphaMaxAnimation();
        }
    }
    float strokeStart = adjustedPercent * .8f;
    mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart));
    mProgress.setArrowScale(Math.min(1f, adjustedPercent));

    float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f;
    mProgress.setProgressRotation(rotation);
    setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop);
}

接着看 setTargetOffsetTopAndBottom 方法 是设置loading 状态显示的方法

void setTargetOffsetTopAndBottom(int offset) {
    mCircleView.bringToFront();
    ViewCompat.offsetTopAndBottom(mCircleView, offset);
    mCurrentTargetOffsetTop = mCircleView.getTop();
}

可以确定swipe是通过moveSpinner 这个方法来 实现弹力计算 主要代码是 有下划线的 几行,现在逐行进行分析。

final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;   

这行代码是 用可以触发滑动距离的结果 乘以弹力系数 0.5(DRAG_RATE

float originalDragPercent = overscrollTop / mTotalDragDistance;

这里是原始的滑动百分比( 滑动距离 乘以系数 得出的值 再除以总最大滑动距离)

float dragPercent = Math.min(1f, Math.abs(originalDragPercent));

这里是过滤最大的百分比如果超过1 就直接取值1

float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;

这里是计算之后的滑动距离减去最大滑动距离得出的 值

float slingshotDist = mUsingCustomStart ? mSpinnerOffsetEnd - mOriginalOffsetTop : mSpinnerOffsetEnd;

滑动超过最大偏移量后可以被允许拖动的最大距离  这儿是判断是否设置最大滑动距离 限制,

一般默认取值mSpinnerOffsetEnd, 

float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2) / slingshotDist);

这里的值为 //当弹簧效果位移小余0时,tensionSlingshotPercent为0,否则取弹簧位移于总高度的比值,最大为2

float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow( (tensionSlingshotPercent / 4), 2)) * 2f;

这里的值为 当滑动位移量超过最大位移量时候计算超过比值,(比值的增长速度正相关,最大值为2,最小值为0) ;   当弹簧效果位移小余0时,tensionSlingshotPercent 以及tensionPercent 为0,否则取位移于总高度的比值,最大为2。这是一个线性函数,当位移小于最大位移量时候 这儿tensionPercent 以及tensionSlingshotPercent  为0,因为,当位移量小于最大位移量的时候extraOS   为负值。

float extraMove = (slingshotDist) * tensionPercent * 2;

这里计算  滑动超过最大偏移量后 滑动的距离,

int targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove);

这里值计算最终 头部 相应的偏移量

下面是测试值截图,

经过打印数据,发现规律。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值