UI实现之下拉刷新:SwipeRefreshLayout PullToRefres
来源:互联网 发布:2017移动互联网数据 编辑:程序博客网 时间:2024/06/02 10:56
UI实现之下拉刷新:SwipeRefreshLayout PullToRefresh
第一个:SwipeRefreshLayout
SwipeRefreshLayout是一个ViewGroup,使用的时候需要在布局文件里添加子View(mTarget),一般是ListView;下拉的时候把ListView整个往下移动并播放动画;
SwipeRefreshLayout继承ViewGroup;onMeasure()、onLayout()中都没有太多内容,跳过直接看onTouchEvent的ACTION_MOVE代码
if(this.mDownEvent != null && !this.mReturningToStart) { float eventY = event.getY(); float yDiff = eventY - this.mDownEvent.getY(); //此处分两步 //第一步:当刚开始下拉的时候会移动mTarget并且动画慢慢出场, //第二步:当下拉到一定程度则mTarget回到原处播放动画 if(yDiff > (float)this.mTouchSlop) { if(yDiff > this.mDistanceToTriggerSync) { //此为第二步 this.startRefresh();//调用播放动画 handled = true; } else { //此为第一步 this.setTriggerPercentage(this.mAccelerateInterpolator.getInterpolation(yDiff / this.mDistanceToTriggerSync));//更新mProgressBar float offsetTop = yDiff; if(this.mPrevY > eventY) { offsetTop = yDiff - (float)this.mTouchSlop; } this.updateContentOffsetTop((int)offsetTop);//移动mTarget if(this.mPrevY > eventY &&this.mTarget.getTop() < this.mTouchSlop) { this.removeCallbacks(this.mCancel); } else { this.updatePositionTimeout();//当手指一定时间不动则重置mTarget和动画 } this.mPrevY = event.getY(); handled = true; } } }
简单来说,这几行代码已经可以把SwipeRefreshLayout的大致运行过程表达清楚了。第一步,用户滑动屏幕的时候,判定用户下滑的距离。小于mDistanceToTriggerSync的时候会去下移mTarget(xml布局中,SwipeRefreshLayout下的子View,一般ListView),同时根据下滑距离改变mProgressBar(即顶部不断变长的颜色条)的进度;同时这里还判断了如果下滑时手指不动一定时间了,则重置mTarget、mProgressBar。第二步,当用户下滑距离大于mDistanceToTriggerSync则mTarget重置,同时播放动画。在这里我们只看onTouchEvent,深入一层层的代码具体实现想知道的可以自己跳进去看;具体mTarget是怎么移动的(最终是调用offsetTopAndBottom方法实现移动的)?mProgressBar是怎么运行动画的(在自定义SwipeProgressBar类里,在onDraw里画出来的)?
最后聊下触摸事件的传递,在SwipeRefreshLayout的onInterceptTouchEvent中会把根据相关状态值(是否可以播放动画或者正在播放中)以及是否是下拉来决定是否拦截改事件。
第二:PushToReresh
https://github.com/MarkMjw/PullToRefresh
这个的原理比较容易理解,XListView继承ListView,通过addHeaderView加入XHeaderView,同时设置其高度为0;下拉时改变XHeaderView的高度,同时让XHeaderView播放动画。XScrollView的原理也是一样,但是XScrollView继承自ScrollView没有HeaderView,所以他加了一个布局,相信大家看下就理解了,三个LinearLayout依次就类似于ListView的HeaderView、ListView、FooterView
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/header_layout" android:layout_gravity="center_horizontal|top" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> <LinearLayout android:id="@+id/content_layout" android:layout_gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> <LinearLayout android:id="@+id/footer_layout" android:layout_gravity="center_horizontal|bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /></LinearLayout>
下面来看看XListView的onTouchEvent的ACTION_MOVE部分
case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); //if分支是下拉刷新,else分支是加载更多(不关心) if (getFirstVisiblePosition() == 0 && (mHeader.getVisibleHeight() > 0 || deltaY > 0)) { // the first item is showing, header has shown or pull down. //关键就是这句,改变XHeaderView的高度 updateHeaderHeight(deltaY / OFFSET_RADIO); //没找到OnXScrollListener的实现,不知道实际干嘛的;注释掉后没发现有啥不对劲 invokeOnScrolling(); } else if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView .getBottomMargin() > 0 || deltaY < 0)) { // last item, already pulled up or want to pull up. updateFooterHeight(-deltaY / OFFSET_RADIO); } break;
现在跟进去updateHeaderHeight看看
private void updateHeaderHeight(float delta) { //调用XHeaderView的方法改变它的高度 mHeader.setVisibleHeight((int) delta + mHeader.getVisibleHeight()); //设置XHeaderView的状态,告诉它应该执行哪个动画了 if (mEnablePullRefresh && !mPullRefreshing) { // update the arrow image unrefreshing if (mHeader.getVisibleHeight() > mHeaderHeight) { //Release to refresh部分 mHeader.setState(XHeaderView.STATE_READY); } else { //Pull to refresh部分 mHeader.setState(XHeaderView.STATE_NORMAL); } } // scroll to top each time //这个地方大家可以注释掉,看看效果;注释掉后下拉之后再往上拉动的时候不止是XHeaderView的高度会变小,ListView也会往上滑动;而它的作用就是把ListView滚动到顶部,这样就可以避免这个问题的发生 setSelection(0); }
相信到这里,整个下拉的大致过程大家已经差不多清楚了,具体还是要自己去看代码。此外想说的是,XListView继承自ListView两种滑动一个View没有办法通过事件onInterceptTouchEvent来解决所以此处采用了setSelection(0)解决;同样的XScrollView是通过下面这段代码来解决的(原理一样,调用函数不同而已),下面看看XScrollView的updateHeaderHeight函数
private void updateHeaderHeight(float delta) { mHeader.setVisibleHeight((int) delta + mHeader.getVisibleHeight()); if (mEnablePullRefresh && !mPullRefreshing) { // update the arrow image unrefreshing if (mHeader.getVisibleHeight() > mHeaderHeight) { mHeader.setState(XHeaderView.STATE_READY); } else { mHeader.setState(XHeaderView.STATE_NORMAL); } } // scroll to top each time //就是它了 post(new Runnable() { @Override public void run() { XScrollView.this.fullScroll(ScrollView.FOCUS_UP); } }); }
再者
还有一个地方在ACTION_UP等地方将一切归于最原始的状态等待下一次的下拉刷新;这里就贴代码了,无非就是重置属性值,将mTarget或XHeaderView重置成原始的位置、状态
最后要说的一个地方就是Animation、Scroller、Interpolator的加入,让整个过程更加自然流畅
小白一枚,学习记录,轻喷~~~
附(开始学UML类图的绘制了。。。):
- UI实现之下拉刷新:SwipeRefreshLayout PullToRefres
- 商城之下拉刷新SwipeRefreshLayout控件介绍
- 四:资讯列表实现(借助PullToRefres实现上拉和下拉刷新)
- 四:资讯列表实现(借助PullToRefres实现上拉和下拉刷新) (下)
- 【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)
- RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout
- 【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)
- RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout
- SwipeRefreshLayout+RecyclerView实现上拉刷新
- SwipeRefreshLayout实现上拉下拉刷新
- 继承SwipeRefreshLayout实现上拉刷新
- Android swiperefreshlayout 实现上拉刷新 加载
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
- 显示文件的某几行 某一行
- objectiveC【语法】修饰符 static extern const
- java 里面的string 和byte[] 怎么互转?
- 191. Number of 1 Bits
- Java—JDK的下载与安装
- UI实现之下拉刷新:SwipeRefreshLayout PullToRefres
- 数据结构之排序查找
- iOS - 社交分享- weibo分享
- android判断是否为手机号码,隐藏中间4位
- 欢迎使用CSDN-markdown编辑器
- 自定义实现strncat函数
- Android 监听apk安装替换卸载广播
- Hadoop的初识
- 1--C语言关键字