PullToRefresh下拉刷新源码分析

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的HeaderViewaddViewInternal方法就是加入到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);//下拉松手 可以松手了}}}

但是至少可以为自己的荷包省钱可以支些招,这点还是很现实的。

PullToRefresh下拉刷新源码分析

相关文章:

你感兴趣的文章:

标签云: