先講下原理:
ScrollView的子View 主要分為3部分:head頭部,滾動內(nèi)容,fooder底部
我們實現(xiàn)慣性滑動,以及回彈,都是靠超過head或者fooder 就重新滾動到? ,內(nèi)容的頂部或者底部。
之前看了Pulltorefresh 他是通過不斷改變 head或者 fooder的 pading 值來實現(xiàn) 上拉或者 下拉的效果。感覺有點不流暢,而且層次嵌套得比較多。當(dāng)然他的好處是擴展性好。
因工作需求,需要層次嵌套少,對性能要求非常高。因此重新自定義了ViewGroup實現(xiàn)。
直接上代碼:
[java] view plain copy
- package?com.example.administrator.customscrollview;??
- ??
- import?android.content.Context;??
- import?android.content.res.TypedArray;??
- import?android.util.AttributeSet;??
- import?android.util.Log;??
- import?android.view.Gravity;??
- import?android.view.MotionEvent;??
- import?android.view.VelocityTracker;??
- import?android.view.View;??
- import?android.view.ViewConfiguration;??
- import?android.view.ViewGroup;??
- import?android.widget.OverScroller;??
- ??
- /**?
- ?*?自定義?pulltorefresh?Layout?
- ?*?TODO:?ferris?2015年9月11日?18:52:40?
- ?*/??
- public?class?PullTorefreshScrollView?extends?ViewGroup?{??
- ??
- ????private?FoodeLayout?fooder_layout;//?top?and?buttom??
- ????private?View?top_layout;??
- ??
- ????private?int?desireWidth,?desireHeight;??
- ????private?VelocityTracker?velocityTracker;??
- ????private?int?mPointerId;??
- ????private?float?x,?y;??
- ????private?OverScroller?mScroller;??
- ????private?int?maxFlingVelocity,?minFlingVelocity;??
- ????private?int?mTouchSlop;??
- ????protected?Boolean?isMove?=?false;??
- ????protected?float?downX?=?0,?downY?=?0;??
- ????private?int?top_hight?=?0;??
- ????private?int?scrollYButtom?=?0;??
- ????private?int?nScrollYButtom?=?0;??
- ??
- ????private?int?pullDownMin?=?0;??
- ????private?Boolean?isEnablePullDown?=?true;??
- ??
- ????private?Boolean?isFirst=true;??
- ??
- ????public?void?setEnablePullDown(Boolean?isEnablePullDown)?{??
- ????????this.isEnablePullDown?=?isEnablePullDown;??
- ????}??
- ??
- ????public?PullTorefreshScrollView(Context?context)?{??
- ????????super(context);??
- ????????init(null,?0);??
- ????}??
- ??
- ????public?PullTorefreshScrollView(Context?context,?AttributeSet?attrs)?{??
- ????????super(context,?attrs);??
- ????????init(attrs,?0);??
- ????}??
- ??
- ????public?PullTorefreshScrollView(Context?context,?AttributeSet?attrs,?int?defStyle)?{??
- ????????super(context,?attrs,?defStyle);??
- ????????init(attrs,?defStyle);??
- ????}??
- ??
- ????private?void?init(AttributeSet?attrs,?int?defStyle)?{??
- ????????//?Load?attributes??
- //????????final?TypedArray?a?=?getContext().obtainStyledAttributes(??
- //????????????????attrs,?R.styleable.PullTorefreshScrollView,?defStyle,?0);??
- //??
- //??
- //????????a.recycle();??
- ????????mScroller?=?new?OverScroller(getContext());??
- ????????maxFlingVelocity?=?ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity();??
- ????????minFlingVelocity?=?ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();??
- ????????mTouchSlop?=?ViewConfiguration.get(getContext()).getScaledTouchSlop();??
- ????}??
- ??
- ????@Override??
- ????protected?void?onFinishInflate()?{??
- ????????super.onFinishInflate();??
- ????????fooder_layout?=?(FoodeLayout)?findViewById(R.id.fooder_layout);??
- ????????top_layout?=?findViewById(R.id.top_layout);??
- ??
- ??
- ????????if?(isEnablePullDown)?{??
- ????????????fooder_layout.showFooderPull();??
- ????????}?else?{??
- ????????????fooder_layout.hideFooder();??
- ????????}??
- ????}??
- ??
- ??
- ????public?int?getScrollYTop()?{??
- ????????return?top_hight;??
- ????}??
- ??
- ????public?int?getScrollYButtom()?{??
- ????????return?scrollYButtom;??
- ????}??
- ??
- ????public?int?getNScrollYTop()?{??
- ????????return?0;??
- ????}??
- ??
- ????public?int?getNScrollYButtom()?{??
- ????????return?nScrollYButtom;??
- ????}??
- ??
- ????public?int?measureWidth(int?widthMeasureSpec)?{??
- ????????int?result?=?0;??
- ????????int?measureMode?=?MeasureSpec.getMode(widthMeasureSpec);??
- ????????int?width?=?MeasureSpec.getSize(widthMeasureSpec);??
- ????????switch?(measureMode)?{??
- ????????????case?MeasureSpec.AT_MOST:??
- ????????????case?MeasureSpec.EXACTLY:??
- ????????????????result?=?width;??
- ????????????????break;??
- ????????????default:??
- ????????????????break;??
- ????????}??
- ????????return?result;??
- ????}??
- ??
- ????public?int?measureHeight(int?heightMeasureSpec)?{??
- ????????int?result?=?0;??
- ????????int?measureMode?=?MeasureSpec.getMode(heightMeasureSpec);??
- ????????int?height?=?MeasureSpec.getSize(heightMeasureSpec);??
- ????????switch?(measureMode)?{??
- ????????????case?MeasureSpec.AT_MOST:??
- ????????????case?MeasureSpec.EXACTLY:??
- ????????????????result?=?height;??
- ????????????????break;??
- ????????????default:??
- ????????????????break;??
- ????????}??
- ????????return?result;??
- ????}??
- ??
- ????@Override??
- ????protected?void?onMeasure(int?widthMeasureSpec,?int?heightMeasureSpec)?{??
- ????????//?計算所有child?view?要占用的空間??
- ????????int?width?=?measureWidth(widthMeasureSpec);??
- ????????int?height?=?measureHeight(heightMeasureSpec);??
- ??
- ????????desireWidth?=?0;??
- ????????desireHeight?=?0;??
- ????????int?count?=?getChildCount();??
- ????????for?(int?i?=?0;?i?<?count;?++i)?{??
- ????????????View?v?=?getChildAt(i);??
- ??
- ????????????if?(v.getVisibility()?!=?View.GONE)?{??
- ??
- ????????????????LayoutParams?lp?=?(LayoutParams)?v.getLayoutParams();??
- ????????????????measureChildWithMargins(v,?widthMeasureSpec,?0,??
- ????????????????????????heightMeasureSpec,?0);??
- ??
- ????????????????//只是在這里增加了垂直或者水平方向的判斷??
- ????????????????if?(v.getId()?==?R.id.top_layout)?{??
- ????????????????????top_hight?=?v.getMeasuredHeight();??
- ????????????????}??
- ????????????????desireWidth?=?Math.max(desireWidth,?v.getMeasuredWidth()??
- ????????????????????????+?lp.leftMargin?+?lp.rightMargin);??
- ????????????????desireHeight?+=?v.getMeasuredHeight()?+?lp.topMargin??
- ????????????????????????+?lp.bottomMargin;??
- ??
- ????????????}??
- ????????}??
- ??
- ????????//?count?with?padding??
- ????????desireWidth?+=?getPaddingLeft()?+?getPaddingRight();??
- ????????desireHeight?+=?getPaddingTop()?+?getPaddingBottom();??
- ??
- ????????//?see?if?the?size?is?big?enough??
- ????????desireWidth?=?Math.max(desireWidth,?getSuggestedMinimumWidth());??
- ????????desireHeight?=?Math.max(desireHeight,?getSuggestedMinimumHeight());??
- ??
- ??
- ????????//處理內(nèi)容比較少的時候,就添加一定的高度??
- ????????int?scrollHight?=?height?+?top_hight?*?2;??
- ????????if?(scrollHight?>?desireWidth)?{??
- ????????????int?offset?=?scrollHight?-?desireHeight;??
- ????????????View?view?=?new?View(getContext());??
- ????????????view.setBackgroundResource(R.color.top_layout_color);??
- ????????????LayoutParams?lp?=?new?LayoutParams(LayoutParams.MATCH_PARENT,?offset);??
- ????????????addView(view,?getChildCount()?-?1,?lp);??
- ????????????desireWidth?=?scrollHight;??
- ????????}??
- ??
- ??
- ????????setMeasuredDimension(resolveSize(desireWidth,?widthMeasureSpec),??
- ????????????????resolveSize(desireHeight,?heightMeasureSpec));??
- ??
- ????????scrollYButtom?=?desireHeight?-?getMeasuredHeight()?-?top_hight;??
- ????????nScrollYButtom?=?desireHeight?-?getMeasuredHeight();??
- ????????//如果上啦拖出一半的高度,就代表將要執(zhí)行上啦??
- ????????pullDownMin?=?nScrollYButtom?-?top_hight?/?2;??
- ????????if(isFirst){??
- ????????????scrollTo(0,?top_hight);??
- ????????????isFirst=false;??
- ????????}??
- ??
- ????}??
- ??
- ????@Override??
- ????protected?void?onLayout(boolean?changed,?int?l,?int?t,?int?r,?int?b)?{??
- ????????final?int?parentLeft?=?getPaddingLeft();??
- ????????final?int?parentRight?=?r?-?l?-?getPaddingRight();??
- ????????final?int?parentTop?=?getPaddingTop();??
- ????????final?int?parentBottom?=?b?-?t?-?getPaddingBottom();??
- ??
- ????????if?(BuildConfig.DEBUG)??
- ????????????Log.d("onlayout",?"parentleft:?"?+?parentLeft?+?"???parenttop:?"??
- ????????????????????+?parentTop?+?"???parentright:?"?+?parentRight??
- ????????????????????+?"???parentbottom:?"?+?parentBottom);??
- ??
- ????????int?left?=?parentLeft;??
- ????????int?top?=?parentTop;??
- ??
- ????????int?count?=?getChildCount();??
- ????????for?(int?i?=?0;?i?<?count;?++i)?{??
- ????????????View?v?=?getChildAt(i);??
- ????????????if?(v.getVisibility()?!=?View.GONE)?{??
- ????????????????LayoutParams?lp?=?(LayoutParams)?v.getLayoutParams();??
- ????????????????final?int?childWidth?=?v.getMeasuredWidth();??
- ????????????????final?int?childHeight?=?v.getMeasuredHeight();??
- ????????????????final?int?gravity?=?lp.gravity;??
- ????????????????final?int?horizontalGravity?=?gravity??
- ????????????????????????&?Gravity.HORIZONTAL_GRAVITY_MASK;??
- ????????????????final?int?verticalGravity?=?gravity??
- ????????????????????????&?Gravity.VERTICAL_GRAVITY_MASK;??
- ??
- ??
- ????????????????//?layout?vertical,?and?only?consider?horizontal?gravity??
- ??
- ????????????????left?=?parentLeft;??
- ????????????????top?+=?lp.topMargin;??
- ????????????????switch?(horizontalGravity)?{??
- ????????????????????case?Gravity.LEFT:??
- ????????????????????????break;??
- ????????????????????case?Gravity.CENTER_HORIZONTAL:??
- ????????????????????????left?=?parentLeft??
- ????????????????????????????????+?(parentRight?-?parentLeft?-?childWidth)?/?2??
- ????????????????????????????????+?lp.leftMargin?-?lp.rightMargin;??
- ????????????????????????break;??
- ????????????????????case?Gravity.RIGHT:??
- ????????????????????????left?=?parentRight?-?childWidth?-?lp.rightMargin;??
- ????????????????????????break;??
- ????????????????}??
- ????????????????v.layout(left,?top,?left?+?childWidth,?top?+?childHeight);??
- ????????????????top?+=?childHeight?+?lp.bottomMargin;??
- ????????????}??
- ??
- ????????}??
- ??
- ??
- ????}??
- ??
- ????@Override??
- ????protected?android.view.ViewGroup.LayoutParams?generateDefaultLayoutParams()?{??
- ????????return?new?LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,??
- ????????????????ViewGroup.LayoutParams.MATCH_PARENT);??
- ????}??
- ??
- ????@Override??
- ????public?android.view.ViewGroup.LayoutParams?generateLayoutParams(??
- ????????????AttributeSet?attrs)?{??
- ????????return?new?LayoutParams(getContext(),?attrs);??
- ????}??
- ??
- ????@Override??
- ????protected?android.view.ViewGroup.LayoutParams?generateLayoutParams(??
- ????????????android.view.ViewGroup.LayoutParams?p)?{??
- ????????return?new?LayoutParams(p);??
- ????}??
- ??
- ????public?static?class?LayoutParams?extends?MarginLayoutParams?{??
- ????????public?int?gravity?=?-1;??
- ??
- ????????public?LayoutParams(Context?c,?AttributeSet?attrs)?{??
- ????????????super(c,?attrs);??
- ??
- ????????????TypedArray?ta?=?c.obtainStyledAttributes(attrs,??
- ????????????????????R.styleable.SlideGroup);??
- ??
- ????????????gravity?=?ta.getInt(R.styleable.SlideGroup_layout_gravity,?-1);??
- ??
- ????????????ta.recycle();??
- ????????}??
- ??
- ????????public?LayoutParams(int?width,?int?height)?{??
- ????????????this(width,?height,?-1);??
- ????????}??
- ??
- ????????public?LayoutParams(int?width,?int?height,?int?gravity)?{??
- ????????????super(width,?height);??
- ????????????this.gravity?=?gravity;??
- ????????}??
- ??
- ????????public?LayoutParams(android.view.ViewGroup.LayoutParams?source)?{??
- ????????????super(source);??
- ????????}??
- ??
- ????????public?LayoutParams(MarginLayoutParams?source)?{??
- ????????????super(source);??
- ????????}??
- ????}??
- ??
- ??
- ????/**?
- ?????*?onInterceptTouchEvent()用來詢問是否要攔截處理。?onTouchEvent()是用來進(jìn)行處理。?
- ?????*?<p/>?
- ?????*?例如:parentLayout----childLayout----childView?事件的分發(fā)流程:?
- ?????*?parentLayout::onInterceptTouchEvent()---false?--->?
- ?????*?childLayout::onInterceptTouchEvent()---false?--->?
- ?????*?childView::onTouchEvent()---false?--->?
- ?????*?childLayout::onTouchEvent()---false?--->?parentLayout::onTouchEvent()?
- ?????*?<p/>?
- ?????*?<p/>?
- ?????*?<p/>?
- ?????*?如果onInterceptTouchEvent()返回false,且分發(fā)的子View的onTouchEvent()中返回true,?
- ?????*?那么onInterceptTouchEvent()將收到所有的后續(xù)事件。?
- ?????*?<p/>?
- ?????*?如果onInterceptTouchEvent()返回true,原本的target將收到ACTION_CANCEL,該事件?
- ?????*?將會發(fā)送給我們自己的onTouchEvent()。?
- ?????*/??
- ????@Override??
- ????public?boolean?onInterceptTouchEvent(MotionEvent?ev)?{??
- ????????final?int?action?=?ev.getActionMasked();??
- ????????if?(BuildConfig.DEBUG)??
- ????????????Log.d("onInterceptTouchEvent",?"action:?"?+?action);??
- ??
- ????????if?(action?==?MotionEvent.ACTION_DOWN?&&?ev.getEdgeFlags()?!=?0)?{??
- ????????????//?該事件可能不是我們的??
- ????????????return?false;??
- ????????}??
- ??
- ????????boolean?isIntercept?=?false;??
- ????????switch?(action)?{??
- ????????????case?MotionEvent.ACTION_DOWN:??
- ????????????????//?如果動畫還未結(jié)束,則將此事件交給onTouchEvet()處理,??
- ????????????????//?否則,先分發(fā)給子View??
- ????????????????isIntercept?=?!mScroller.isFinished();??
- ????????????????//?如果此時不攔截ACTION_DOWN時間,應(yīng)該記錄下觸摸地址及手指id,當(dāng)我們決定攔截ACTION_MOVE的event時,??
- ????????????????//?將會需要這些初始信息(因為我們的onTouchEvent將可能接收不到ACTION_DOWN事件)??
- ????????????????mPointerId?=?ev.getPointerId(0);??
- //??????????if?(!isIntercept)?{??
- ????????????????downX?=?x?=?ev.getX();??
- ????????????????downY?=?y?=?ev.getY();??
- //??????????}??
- ????????????????break;??
- ????????????case?MotionEvent.ACTION_MOVE:??
- ????????????????int?pointerIndex?=?ev.findPointerIndex(mPointerId);??
- ????????????????if?(BuildConfig.DEBUG)??
- ????????????????????Log.d("onInterceptTouchEvent",?"pointerIndex:?"?+?pointerIndex??
- ????????????????????????????+?",?pointerId:?"?+?mPointerId);??
- ????????????????float?mx?=?ev.getX(pointerIndex);??
- ????????????????float?my?=?ev.getY(pointerIndex);??
- ??
- ????????????????if?(BuildConfig.DEBUG)??
- ????????????????????Log.d("onInterceptTouchEvent",?"action_move?[touchSlop:?"??
- ????????????????????????????+?mTouchSlop?+?",?deltaX:?"?+?(x?-?mx)?+?",?deltaY:?"??
- ????????????????????????????+?(y?-?my)?+?"]");??
- ??
- ????????????????//?根據(jù)方向進(jìn)行攔截,(其實這樣,如果我們的方向是水平的,里面有一個ScrollView,那么我們是支持嵌套的)??
- ??
- ????????????????if?(Math.abs(y?-?my)?>=?mTouchSlop)?{??
- ????????????????????isIntercept?=?true;??
- ????????????????}??
- ??
- ??
- ????????????????//如果不攔截的話,我們不會更新位置,這樣可以通過累積小的移動距離來判斷是否達(dá)到可以認(rèn)為是Move的閾值。??
- ????????????????//這里當(dāng)產(chǎn)生攔截的話,會更新位置(這樣相當(dāng)于損失了mTouchSlop的移動距離,如果不更新,可能會有一點點跳的感覺)??
- ????????????????if?(isIntercept)?{??
- ????????????????????x?=?mx;??
- ????????????????????y?=?my;??
- ????????????????}??
- ????????????????break;??
- ????????????case?MotionEvent.ACTION_CANCEL:??
- ????????????case?MotionEvent.ACTION_UP:??
- ????????????????//?這是觸摸的最后一個事件,無論如何都不會攔截??
- ????????????????if?(velocityTracker?!=?null)?{??
- ????????????????????velocityTracker.recycle();??
- ????????????????????velocityTracker?=?null;??
- ????????????????}??
- ????????????????break;??
- ????????????case?MotionEvent.ACTION_POINTER_UP:??
- ????????????????solvePointerUp(ev);??
- ??
- ????????????????break;??
- ????????}??
- ????????return?isIntercept;??
- ????}??
- ??
- ????private?void?solvePointerUp(MotionEvent?event)?{??
- ????????//?獲取離開屏幕的手指的索引??
- ????????int?pointerIndexLeave?=?event.getActionIndex();??
- ????????int?pointerIdLeave?=?event.getPointerId(pointerIndexLeave);??
- ????????if?(mPointerId?==?pointerIdLeave)?{??
- ????????????//?離開屏幕的正是目前的有效手指,此處需要重新調(diào)整,并且需要重置VelocityTracker??
- ????????????int?reIndex?=?pointerIndexLeave?==?0???1?:?0;??
- ????????????mPointerId?=?event.getPointerId(reIndex);??
- ????????????//?調(diào)整觸摸位置,防止出現(xiàn)跳動??
- ????????????x?=?event.getX(reIndex);??
- ????????????y?=?event.getY(reIndex);??
- ????????????if?(velocityTracker?!=?null)??
- ????????????????velocityTracker.clear();??
- ????????}??
- ????}??
- ??
- ????@Override??
- ????public?boolean?onTouchEvent(MotionEvent?event)?{??
- ??
- ????????final?int?action?=?event.getActionMasked();??
- ??
- ????????if?(velocityTracker?==?null)?{??
- ????????????velocityTracker?=?VelocityTracker.obtain();??
- ????????}??
- ????????velocityTracker.addMovement(event);??
- ??
- ????????switch?(action)?{??
- ????????????case?MotionEvent.ACTION_DOWN:??
- ????????????????//?獲取索引為0的手指id??
- ??
- ??
- ????????????????isMove?=?false;??
- ????????????????mPointerId?=?event.getPointerId(0);??
- ????????????????x?=?event.getX();??
- ????????????????y?=?event.getY();??
- ????????????????if?(!mScroller.isFinished())??
- ????????????????????mScroller.abortAnimation();??
- ????????????????break;??
- ????????????case?MotionEvent.ACTION_MOVE:??
- ????????????????isMove?=?true;??
- ????????????????//?獲取當(dāng)前手指id所對應(yīng)的索引,雖然在ACTION_DOWN的時候,我們默認(rèn)選取索引為0??
- ????????????????//?的手指,但當(dāng)有第二個手指觸摸,并且先前有效的手指up之后,我們會調(diào)整有效手指??
- ??
- ????????????????//?屏幕上可能有多個手指,我們需要保證使用的是同一個手指的移動軌跡,??
- ????????????????//?因此此處不能使用event.getActionIndex()來獲得索引??
- ????????????????final?int?pointerIndex?=?event.findPointerIndex(mPointerId);??
- ????????????????float?mx?=?event.getX(pointerIndex);??
- ????????????????float?my?=?event.getY(pointerIndex);??
- ??
- ????????????????moveBy((int)?(x?-?mx),?(int)?(y?-?my));??
- ??
- ????????????????x?=?mx;??
- ????????????????y?=?my;??
- ????????????????break;??
- ????????????case?MotionEvent.ACTION_UP:??
- ????????????????isMove?=?false;??
- ????????????????velocityTracker.computeCurrentVelocity(1000,?maxFlingVelocity);??
- ????????????????float?velocityX?=?velocityTracker.getXVelocity(mPointerId);??
- ????????????????float?velocityY?=?velocityTracker.getYVelocity(mPointerId);??
- ??
- ????????????????completeMove(-velocityX,?-velocityY);??
- ????????????????if?(velocityTracker?!=?null)?{??
- ????????????????????velocityTracker.recycle();??
- ????????????????????velocityTracker?=?null;??
- ????????????????}??
- ????????????????break;??
- ??
- ????????????case?MotionEvent.ACTION_POINTER_UP:??
- ????????????????//?獲取離開屏幕的手指的索引??
- ????????????????isMove?=?false;??
- ????????????????int?pointerIndexLeave?=?event.getActionIndex();??
- ????????????????int?pointerIdLeave?=?event.getPointerId(pointerIndexLeave);??
- ????????????????if?(mPointerId?==?pointerIdLeave)?{??
- ????????????????????//?離開屏幕的正是目前的有效手指,此處需要重新調(diào)整,并且需要重置VelocityTracker??
- ????????????????????int?reIndex?=?pointerIndexLeave?==?0???1?:?0;??
- ????????????????????mPointerId?=?event.getPointerId(reIndex);??
- ????????????????????//?調(diào)整觸摸位置,防止出現(xiàn)跳動??
- ????????????????????x?=?event.getX(reIndex);??
- ????????????????????y?=?event.getY(reIndex);??
- ????????????????????if?(velocityTracker?!=?null)??
- ????????????????????????velocityTracker.clear();??
- ????????????????}??
- ????????????????break;??
- ????????????case?MotionEvent.ACTION_CANCEL:??
- ????????????????isMove?=?false;??
- ????????????????break;??
- ????????}??
- ????????return?true;??
- ????}??
- ??
- ????private?Boolean?isPull?=?false;??
- ??
- ????//此處的moveBy是根據(jù)水平或是垂直排放的方向,??
- //來選擇是水平移動還是垂直移動??
- ????public?void?moveBy(int?deltaX,?int?deltaY)?{??
- ????????if?(BuildConfig.DEBUG)??
- ????????????Log.d("moveBy",?"deltaX:?"?+?deltaX?+?"????deltaY:?"?+?deltaY);??
- ????????if?(Math.abs(deltaY)?>=?Math.abs(deltaX))?{??
- ????????????int?mScrollY?=?getScrollY();??
- ????????????if?(mScrollY?<=?0)?{??
- ????????????????scrollTo(0,?0);??
- ????????????}?else?if?(mScrollY?>=?getNScrollYButtom())?{??
- ????????????????scrollTo(0,?getNScrollYButtom());??
- ??
- ??
- ????????????}?else?{??
- ????????????????scrollBy(0,?deltaY);??
- ????????????}??
- ??
- ????????????if?(isEnablePullDown?&&?deltaY?>?0?&&?mScrollY?>=?pullDownMin)?{??
- ????????????????isPull?=?true;??
- ????????????????Log.d("onlayout",?"isPull:?true");??
- ????????????}??
- ????????}??
- ??
- ??
- ????}??
- ??
- ????private?void?completeMove(float?velocityX,?float?velocityY)?{??
- ??
- ????????int?mScrollY?=?getScrollY();??
- ????????int?maxY?=?getScrollYButtom();??
- ????????int?minY?=?getScrollYTop();??
- ??
- ??
- ????????if?(mScrollY?>=?maxY)?{//如果滾動,超過了?下邊界,就回彈到下邊界??
- ??
- ????????????if?(isPull)?{//滾動到最底部??
- ????????????????mScroller.startScroll(0,?mScrollY,?0,?getNScrollYButtom()?-?mScrollY,?300);??
- ????????????????invalidate();??
- ??
- ????????????????//顯示雷達(dá)??
- ????????????????fooder_layout.showFooderRadar();??
- ????????????????if?(pullDownListem?!=?null)?{??
- ????????????????????pullDownListem.onPullDown();??
- ????????????????}??
- ????????????????Log.d("onlayout",?"isPull:?true?滾動到最底部,顯示出雷達(dá)");??
- ??
- ????????????}?else?{??
- ????????????????mScroller.startScroll(0,?mScrollY,?0,?maxY?-?mScrollY);??
- ????????????????invalidate();??
- ????????????????Log.d("onlayout",?"isPull:?true");??
- ????????????}??
- ??
- ????????}?else?if?(mScrollY?<=?minY)?{//如果滾動,超過了上邊界,就回彈到上邊界??
- ????????????//?超出了上邊界,彈回??
- ????????????mScroller.startScroll(0,?mScrollY,?0,?minY?-?mScrollY);??
- ????????????invalidate();??
- ????????}?else?if?(Math.abs(velocityY)?>=?minFlingVelocity?&&?maxY?>?0)?{//大于1頁的時候??
- //????????????mScroller.fling(0,?mScrollY,?0,?(int)?(velocityY?*?1.2f),?0,?0,?minY,?maxY);??
- ????????????mScroller.fling(0,?mScrollY,?0,?(int)?(velocityY?*?2f),?0,?0,?getNScrollYTop(),?getNScrollYButtom());??
- ????????????invalidate();??
- ????????}??
- ??
- ??
- ????}??
- ??
- ??
- ????public?void?ifNeedScrollBack()?{??
- ????????int?mScrollY?=?getScrollY();??
- ????????int?maxY?=?getScrollYButtom();??
- ????????int?minY?=?getScrollYTop();??
- ????????if?(mScrollY?>?maxY)?{??
- ????????????//?超出了下邊界,彈回??
- ????????????mScroller.startScroll(0,?mScrollY,?0,?maxY?-?mScrollY);??
- ??
- ????????????invalidate();??
- ??
- ????????}?else?if?(mScrollY?<?minY)?{??
- ????????????//?超出了上邊界,彈回??
- ????????????mScroller.startScroll(0,?mScrollY,?0,?minY?-?mScrollY);??
- ????????????invalidate();??
- ????????}??
- ????}??
- ??
- ????@Override??
- ????protected?void?onScrollChanged(int?l,?int?t,?int?oldl,?int?oldt)?{??
- ????????super.onScrollChanged(l,?t,?oldl,?oldt);??
- ????}??
- ??
- ????@Override??
- ????public?void?computeScroll()?{??
- ????????if?(mScroller.computeScrollOffset())?{??
- ??
- ????????????scrollTo(0,?mScroller.getCurrY());??
- ??
- ????????????postInvalidate();??
- ??
- ????????}?else?{??
- ????????????Log.d("onlayout",?"computeScroll,isMove:"+isMove+",isPull:"+isPull);??
- ????????????if?(!isMove?&&?!isPull)?{??
- ????????????????ifNeedScrollBack();??
- ????????????}??
- ??
- ????????}??
- ????}??
- ??
- ??
- ????public?void?onPullSuccess()?{??
- ??
- ????????soomToBack();??
- ????}??
- ??
- ????public?void?soomToBack()?{??
- ????????int?mScrollY?=?getScrollY();??
- ????????int?maxY?=?getScrollYButtom();??
- ????????Log.d("onlayout",?"soomToBack:?(maxY?-?mScrollY)="+(maxY?-?mScrollY)+",maxY="+maxY+",mScrollY="+mScrollY);??
- ????????//?超出了下邊界,彈回??
- ????????mScroller.startScroll(0,?mScrollY,?0,?maxY?-?mScrollY,?300);??
- ????????invalidate();??
- ????????postDelayed(new?Runnable()?{??
- ????????????@Override??
- ????????????public?void?run()?{??
- ????????????????fooder_layout.showFooderPull();??
- ????????????????isPull?=?false;??
- ????????????}??
- ????????},?310);??
- ??
- ??
- ????}??
- ??
- ????private?PullDownListem?pullDownListem;??
- ??
- ????public?void?setPullDownListem(PullDownListem?pullDownListem)?{??
- ????????this.pullDownListem?=?pullDownListem;??
- ????}??
- ??
- ????public?interface?PullDownListem?{??
- ??
- ????????public?void?onPullDown();??
- ??
- ????}??
- }?
本文摘自 :https://blog.51cto.com/u