您好,登錄后才能下訂單哦!
本文實例為大家分享了Android實現下拉刷新和上拉加載更多的具體代碼,供大家參考,具體內容如下
先分享下源碼:Android實現下拉刷新和上拉加載更多
實現思路:由PullRefreshViewGroup控件來接管標準控件(比如RecyclerView、ListView等)的滑動,調用標準控件的內部方法進行短距離滑動,不再由標準控件自己來處理事件,而完全由PullRefreshViewGroup控件來處理觸摸事件。標準控件內部的滑動距離等屬性,通過反射獲得computeVerticalScrollExtent、computeVerticalScrollRange、computeVerticalScrollOffset這三個方法來獲得。
PullRefreshViewGroup控件的布局如下
部分代碼實現
觸摸滑動事件處理
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean bret = false; switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { mPreY = ev.getY(); Log.d(TAG, "mPreY:" + String.valueOf(mPreY)); } break; case MotionEvent.ACTION_MOVE: { float curY = ev.getY(); float distance = curY - mPreY; if (Math.abs(distance) >= mTouchSlop) { mSliding = bret = true; //修正第一次滑動的卡頓 if (distance > 0) { mPreY += mTouchSlop; } else { mPreY -= mTouchSlop; } if (!mScroller.isFinished()) { mScroller.abortAnimation(); } } else { mSliding = bret = false; } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { bret = mSliding; } break; } return bret ? true : super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { boolean bret = false; vTracker.addMovement(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { mPreY = event.getY(); bret = true; } break; case MotionEvent.ACTION_MOVE: { float curY = event.getY(); float distance = curY - mPreY; Log.d(TAG, "mPreY:" + String.valueOf(mPreY) + " distance:" + String.valueOf(distance)); if (distance != 0) { bret = true; if (mSrcHeightHead == -1 && mHasPullRefresh) { View child0View = mHeadView; mSrcHeightHead = child0View.getHeight(); } scrollBy(distance); } mPreY = curY; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { mPreCurY = 0; View child0View = mHeadView; int child0Height = null != child0View ? child0View.getHeight() : 0; int child0Height2 = null != child0View ? child0View.getLayoutParams().height : 0; //視圖的最終高度是有這個來決定的,請看onMeasure 函數的實現 // int child0Height3 = child0View.getMeasuredHeight(); if (child0Height2 != child0Height) { child0Height = child0Height2; } int child0Top = null != child0View ? child0View.getTop() : 0; int dy = child0Height - mSrcHeightHead + (mSrcHeightHead - Math.abs(child0Top)); Log.d(TAG, "onTouchEvent()ACTION_UP child0Height:" + String.valueOf(child0Height) + " mSrcHeightHead:" + String.valueOf(mSrcHeightHead) + " child0Top:" + String.valueOf(child0Top)); if (dy > 0) {//恢復拉伸視圖的位置 if (!mLoadingMore && dy > mCanRefreshHeight && child0Top + child0Height2 > mCanRefreshHeight && mRefreshLoad != null) { dy -= mCanRefreshHeight; if (!mPullRefreshLoading) { mPullRefreshLoading = true; mTvRefreshInfo.setText("正在加載..."); mRefreshLoad.pullRefreshStartLoad(); } } mScroller.startScroll(0, 0, 0, -dy); invalidate(); } else { vTracker.computeCurrentVelocity(1000); float yvel = vTracker.getYVelocity(); if (yvel != 0) {//為了滿足內部視圖的快速滾動( 中間內容視圖 ) mScroller.fling(0, 0, 0, (int) yvel, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE); invalidate(); } } vTracker.clear(); bret = true; } break; } return bret ? true : super.onTouchEvent(event); }
小距離滑動代碼
private void scrollBy(float distance) { View child0View = mHeadView; View child1View = getChildAt(null == mHeadView ? 0 : 1); float distanceRemain = 0; int child0Top = null != child0View ? child0View.getTop() : 0; // int child0Height = child0View.getHeight(); if (distance < 0) {//向上 int child1Top = child1View.getTop(); // int child1Height = child1View.getHeight(); //child0View 縮小 if (-1 != mSrcHeightHead && null != child0View && child0View.getHeight() > mSrcHeightHead) { float off = distance; if (child0View.getHeight() + distance < mSrcHeightHead) { off = -(child0View.getHeight() - mSrcHeightHead); distance -= off; } else { distance = 0; } child0View.getLayoutParams().height += (int) off; child1Top += (int) off; //child0view 縮小的同時, child1view 的高度也會隨之上升 這里很重要 requestLayout(); child1View.offsetTopAndBottom((int) off); if (null != mTailView) { mTailView.offsetTopAndBottom((int) off); } } if (distance != 0) { if (child0Top + mSrcHeightHead + distance <= 0) { distanceRemain = -(distance + (child0Top + mSrcHeightHead));//正數 distance = -(child0Top + mSrcHeightHead);//負數 } //可以顯示加載更多嗎? boolean bDirectDown = false; boolean bCanScroll = child1View.canScrollVertically(1) || child1View.canScrollVertically(-1); if (!bCanScroll) { int child1ChildCount = 0; if (child1View instanceof ViewGroup) { child1ChildCount = ((ViewGroup) child1View).getChildCount(); } if (child1ChildCount > 0) { ViewGroup viewGroupChild1 = (ViewGroup) child1View; View child1LastItem = viewGroupChild1.getChildAt(child1ChildCount - 1); int child1ViewBottom = viewGroupChild1.getBottom(); int child1LastItemBottom = child1LastItem.getBottom() + child1Top; //相對于 ImageScaleViewGroup 的位置 //增加 child1ViewBottom > getHeight() 來控制 ScrollView if (child1LastItemBottom == getHeight()) { bDirectDown = true; } } } //正在下拉刷新的時候,不能顯示加載更多 if ((bCanScroll || bDirectDown) && null != mTailView && !mPullRefreshLoading) { int nVerticalScrollExtent = 0, nVerticalScrollRange = 0, nVerticalScrollOffset = 0; Class c = null; try { c = Class.forName(child1View.getClass().getName()); } catch (Exception ex) { } try { if (null == mComputeVerticalScrollExtent) { Method computeVerticalScrollExtent = findcomputeVerticalMethod(c, "computeVerticalScrollExtent"); computeVerticalScrollExtent.setAccessible(true); mComputeVerticalScrollExtent = computeVerticalScrollExtent; } nVerticalScrollExtent = (int) mComputeVerticalScrollExtent.invoke(child1View); } catch (Exception ex) { } try { if (null == mComputeVerticalScrollRange) { Method computeVerticalScrollRange = findcomputeVerticalMethod(c, "computeVerticalScrollRange"); computeVerticalScrollRange.setAccessible(true); mComputeVerticalScrollRange = computeVerticalScrollRange; } nVerticalScrollRange = (int) mComputeVerticalScrollRange.invoke(child1View); } catch (Exception ex) { } try { if (null == mComputeVerticalScrollOffset) { Method computeVerticalScrollOffset = findcomputeVerticalMethod(c, "computeVerticalScrollOffset"); computeVerticalScrollOffset.setAccessible(true); mComputeVerticalScrollOffset = computeVerticalScrollOffset; } nVerticalScrollOffset = (int) mComputeVerticalScrollOffset.invoke(child1View); } catch (Exception ex) { } int range = nVerticalScrollRange - nVerticalScrollExtent; if (nVerticalScrollOffset + distanceRemain > range) { float nOff = distanceRemain - (range - nVerticalScrollOffset); distanceRemain = range - nVerticalScrollOffset; distance -= nOff; } int child3Bottom = mTailView.getBottom(); if (child3Bottom + distance < getHeight()) { distance = getHeight() - child3Bottom; } } if (!bCanScroll) { distanceRemain = 0; } } } else {//向下 int nScrollOffset = 0; try { Class c = Class.forName(child1View.getClass().getName()); Method computeVerticalScrollOffset = findcomputeVerticalMethod(c, "computeVerticalScrollOffset");//c.getDeclaredMethod("computeVerticalScrollOffset"); computeVerticalScrollOffset.setAccessible(true); nScrollOffset = (int) computeVerticalScrollOffset.invoke(child1View); } catch (Exception ex) { } int child2Top = null != mTailView ? mTailView.getTop() : getHeight();//注意默認值 if (child2Top < getHeight()) { if (child2Top + distance > getHeight()) { distanceRemain = distance - (getHeight() - child2Top); distance = getHeight() - child2Top; } } else if (nScrollOffset > 0) {//內部有滾動,那么就要計算內部滾動距離,其他分配給整體滾動 if (nScrollOffset - distance <= 0) { distanceRemain = -nScrollOffset; // distance = distance - nScrollOffset; distance = 0; //內部能滾動,不讓外部去滾動 if (!mScroller.isFinished()) { mScroller.abortAnimation(); //內部滾動完后,立即停止 } } else { distanceRemain = -distance;//負數 distance = 0; } } else { if (child0Top + distance > 0) {//child0放大,child1移動 int off = (int) (child0Top + distance); distance = -child0Top; if (null != child0View) { child0View.getLayoutParams().height += off; requestLayout(); } else { off = 0; } child1View.offsetTopAndBottom(off); if (null != mTailView) { mTailView.offsetTopAndBottom(off); } } } } if (0 != (int) distance) { if (null != child0View) { child0View.offsetTopAndBottom((int) distance); } child1View.offsetTopAndBottom((int) distance); if (null != mTailView) { mTailView.offsetTopAndBottom((int) distance); } requestLayout();//奇酷360這里必須調用, 否則顯示有點問題 } scrollByForMidView(distanceRemain);//外部無法滾動的時候,內部滾動 if (!mPullRefreshLoading && !mLoadingMore) { int tailviewTop = null != mTailView ? mTailView.getTop() : getHeight();//注意默認值 if (tailviewTop < getHeight() && mHasLoadMore) {//加載更多 mLoadingMore = true; if (mRefreshLoad != null) { mRefreshLoad.pullUpStartLoadMore(); } } else { if (mHasPullRefresh) { if (distance < 0) { int child0Bottom = child0View.getBottom(); if (child0Bottom < mCanRefreshHeight) { mTvRefreshInfo.setText("下拉刷新"); } } else { int child0Bottom = child0View.getBottom(); if (child0Bottom > mCanRefreshHeight) { mTvRefreshInfo.setText("松開刷新"); } } } } } }
處理標準控件小距離滾動代碼,這里ListView有點特殊。
private void scrollByForMidView(float distanceRemain) { if (0 != (int) distanceRemain) { View child1View = getChildAt(null == mHeadView ? 0 : 1); if (child1View instanceof ListView) { ((ListView) child1View).smoothScrollBy((int) distanceRemain, 0); } /*else if (child1View instanceof ScrollView){ ((ScrollView) child1View).smoothScrollBy(0,(int) distanceRemain); }*/ else { child1View.scrollBy(0, (int) distanceRemain); } } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。