打开源码发现 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);
这里值计算最终 头部 相应的偏移量
下面是测试值截图,
经过打印数据,发现规律。