開源Android-PullToRefresh下拉重新整理源碼分析,androidpulltorefresh

來源:互聯網
上載者:User

開源Android-PullToRefresh下拉重新整理源碼分析,androidpulltorefresh

  PullToRefresh 這個庫用的是非常至多,github  今天主要分析一下源碼實現.

我們通過ListView的下拉重新整理進行分析,其它的類似。

整個下拉重新整理  父View是LinearLayout, 在LinearLayout添加了Header View ,Footer View,和ListView

PullToRefreshBase 是父類 擴充了 LinearLayout水平布局   如果我們使用ListView 需要觀看子類  PullToRefreshAdapterViewBase -> PullToRefreshListView  


 初始化代碼在PullToRefreshBase init方法中

重點代碼:

// Refreshable View// By passing the attrs, we can add ListView/GridView params via XMLmRefreshableView = createRefreshableView(context, attrs);//通過子類傳入的View,ListView或者ScrollView等addRefreshableView(context, mRefreshableView);//添加view到布局中// We need to create now layouts now  建立Header和Footer視圖,預設是INVISIBLE,要添加到父視窗mHeaderLayout = createLoadingLayout(context, Mode.PULL_FROM_START, a);mFooterLayout = createLoadingLayout(context, Mode.PULL_FROM_END, a);handleStyledAttributes(a);//添加loadingView效果,這裡是把View添加到ListView HeaderView裡面去updateUIForMode(); //把布局添加到父View中

protected void updateUIForMode() {final LinearLayout.LayoutParams lp = getLoadingLayoutLayoutParams();// Remove Header, and then add Header Loading View again if neededif (this == mHeaderLayout.getParent()) {removeView(mHeaderLayout);}if (mMode.showHeaderLoadingLayout()) {addViewInternal(mHeaderLayout, 0, lp);//加入View到LinearLayout}// Remove Footer, and then add Footer Loading View again if neededif (this == mFooterLayout.getParent()) {removeView(mFooterLayout);}if (mMode.showFooterLoadingLayout()) {addViewInternal(mFooterLayout, lp);//加入View到LinearLayout}// Hide Loading ViewsrefreshLoadingViewsSize();//把headerView隱藏起來,其實用的是padding的方式 設定為負值 就到螢幕頂部的外面了 // If we're not using Mode.BOTH, set mCurrentMode to mMode, otherwise// set it to pull downmCurrentMode = (mMode != Mode.BOTH) ? mMode : Mode.PULL_FROM_START;}

//這裡有2個LoadingView,一個是加入到LinearLayout中去了,還有一個是加入到ListView本身的Header裡面

看看handleStyledAttributes方法 定位到子類複寫的地方

FrameLayout frame = new FrameLayout(getContext());
mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a);
mHeaderLoadingView.setVisibility(View.GONE);
frame.addView(mHeaderLoadingView, lp);
mRefreshableView.addHeaderView(frame, null, false);//添加LoadingView到ListView Header上

        //headerView一共有2個LoadingView,一個是被加入到LinearLayout一個是被加入到ListView的HeaderView
addViewInternal方法就是加入到LinearLayout父類中 


看看LoadingLayout 有2種  FlipLoadingLayout 和  RotateLoadingLayout 一般我們用旋轉的載入動畫
左邊一個旋轉圖片,右邊是文字和時間提示
    
第一個LoadingLayout主要顯示 :下拉重新整理,放開以重新整理
第二個LoadingLayout顯示鬆手後的文字:正在載入...

結構是這樣



當UI初始化好,下面看看onTouch 下拉捕獲事件


public final boolean onTouchEvent(MotionEvent event) {if (!isPullToRefreshEnabled()) {return false;}// If we're refreshing, and the flag is set. Eat the eventif (!mScrollingWhileRefreshingEnabled && isRefreshing()) {return true;}if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {return false;}switch (event.getAction()) {case MotionEvent.ACTION_MOVE: {if (mIsBeingDragged) {mLastMotionY = event.getY();mLastMotionX = event.getX();pullEvent();//開始下拉,移動 return true;}break;}case MotionEvent.ACTION_DOWN: {if (isReadyForPull()) {//按下 開始下拉mLastMotionY = mInitialMotionY = event.getY();mLastMotionX = mInitialMotionX = event.getX();return true;}break;}case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP: { //停止下拉的時候if (mIsBeingDragged) {mIsBeingDragged = false;if (mState == State.RELEASE_TO_REFRESH&& (null != mOnRefreshListener || null != mOnRefreshListener2)) {setState(State.REFRESHING, true);//放下手指開始回調,執行我們的回調任務return true;}// If we're already refreshing, just scroll back to the topif (isRefreshing()) {smoothScrollTo(0);return true;}// If we haven't returned by here, then we're not in a state// to pull, so just resetsetState(State.RESET); //恢複到原來的UI狀態return true;}break;}}return false;}


看看pullEvent方法private void pullEvent() {final int newScrollValue;final int itemDimension;final float initialMotionValue, lastMotionValue;switch (getPullToRefreshScrollDirection()) {case HORIZONTAL:initialMotionValue = mInitialMotionX;lastMotionValue = mLastMotionX;break;case VERTICAL:default:initialMotionValue = mInitialMotionY;lastMotionValue = mLastMotionY;break;}//計算下拉移動了多少switch (mCurrentMode) {case PULL_FROM_END://上拉newScrollValue = Math.round(Math.max(initialMotionValue - lastMotionValue, 0) / FRICTION);itemDimension = getFooterSize();break;case PULL_FROM_START://下拉default:newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / FRICTION);itemDimension = getHeaderSize();break;}//顯示HeaderView 得到移動的值,可以讓LoadingView顯示出來setHeaderScroll(newScrollValue);if (newScrollValue != 0 && !isRefreshing()) {float scale = Math.abs(newScrollValue) / (float) itemDimension;switch (mCurrentMode) {case PULL_FROM_END:mFooterLayout.onPull(scale);break;case PULL_FROM_START:default: mHeaderLayout.onPull(scale);//旋轉左邊的載入圖片,顯示文字和圖片 這個地方最終會執行LoadingLayout中的 onPullImpl方法break;}//更新狀態 包括2中 釋放按下觸摸,還有就是 沒釋放手的觸摸if (mState != State.PULL_TO_REFRESH && itemDimension >= Math.abs(newScrollValue)) {setState(State.PULL_TO_REFRESH);} else if (mState == State.PULL_TO_REFRESH && itemDimension < Math.abs(newScrollValue)) {setState(State.RELEASE_TO_REFRESH);//下拉鬆手 可以鬆手了}}}



再看看setHeaderScroll方法代碼protected final void setHeaderScroll(int value) {if (DEBUG) {Log.d(LOG_TAG, "setHeaderScroll: " + value);}if (DEBUG) {Log.d(LOG_TAG, "setHeaderScroll:" + value );}// Clamp value to with pull scroll rangefinal int maximumPullScroll = getMaximumPullScroll();value = Math.min(maximumPullScroll, Math.max(-maximumPullScroll, value));if (mLayoutVisibilityChangesEnabled) {if (value < 0) { //有位移才顯示mHeaderLayout.setVisibility(View.VISIBLE);} else if (value > 0) {  <span style="font-family: Arial, Helvetica, sans-serif;">//有位移才顯示</span>mFooterLayout.setVisibility(View.VISIBLE);} else { mHeaderLayout.setVisibility(View.INVISIBLE);mFooterLayout.setVisibility(View.INVISIBLE);}}if (USE_HW_LAYERS) {/** * Use a Hardware Layer on the Refreshable View if we've scrolled at * all. We don't use them on the Header/Footer Views as they change * often, which would negate any HW layer performance boost. */ViewCompat.setLayerType(mRefreshableViewWrapper, value != 0 ? View.LAYER_TYPE_HARDWARE: View.LAYER_TYPE_NONE);}//回到最原始的scrollTo 最常用的 移動布局switch (getPullToRefreshScrollDirection()) {case VERTICAL:scrollTo(0, value);break;case HORIZONTAL:scrollTo(value, 0);break;}}

setState(State.REFRESHING, true);//拉倒最頂部 鬆手,會執行onRefreshing方法,回調我們實現的任務介面 也就是OnRefreshListener


protected void onRefreshing(final boolean doScroll) {if (mMode.showHeaderLoadingLayout()) {mHeaderLayout.refreshing();}if (mMode.showFooterLoadingLayout()) {mFooterLayout.refreshing();}if (doScroll) {if (mShowViewWhileRefreshing) {// Call Refresh Listener when the Scroll has finishedOnSmoothScrollFinishedListener listener = new OnSmoothScrollFinishedListener() {@Overridepublic void onSmoothScrollFinished() {callRefreshListener();//回調介面執行}};switch (mCurrentMode) {case MANUAL_REFRESH_ONLY:case PULL_FROM_END:smoothScrollTo(getFooterSize(), listener);break;default:case PULL_FROM_START:smoothScrollTo(-getHeaderSize(), listener);break;}} else {smoothScrollTo(0);//回到原來的位置}} else {// We're not scrolling, so just call Refresh Listener nowcallRefreshListener();//回調介面執行}}



private void callRefreshListener() {if (null != mOnRefreshListener) {mOnRefreshListener.onRefresh(this);//回調} else if (null != mOnRefreshListener2) { //這個是上拉,下拉都可以的情況,使用 onRefreshListener2if (mCurrentMode == Mode.PULL_FROM_START) {mOnRefreshListener2.onPullDownToRefresh(this);} else if (mCurrentMode == Mode.PULL_FROM_END) {mOnRefreshListener2.onPullUpToRefresh(this);}}}

總結:狀態包括下拉重新整理,鬆手重新整理,正在重新整理,Loading隱藏。移動UI還是用的scrollTo最基本的代碼. 動畫部分可以看LoadingLayout的2個子類

主要的就這些,還有很多細節沒有分析。若有問題請指出謝謝。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.