直接進入主題,先來看一下京東的實現效果:
jd.gif
以及我自己的實現效果:
myjd.gif
實現過程
1.下拉原理
layout.png
整個布局為繼承自LinearLayout的Viewgroup,分為頭部及下面的列表部分,通過設置HeaderView的topMargin屬性為負使HeaderView向屏幕上方偏移。
初始化時設置HeaderView的topMargin為負的HeaderView的高度可以將HeaderView完全隱藏,從而屏幕中只看得到列表部分。下拉過程中根據手指劃過的距離不斷更新HeaderView的topMargin值來改變HeaderView的可視范圍從而達到下拉的效果。
2.效果實現
觀察京東客戶端的下拉過程,可以看出下拉過程中快遞員和包裹是不斷放大的并且透明度在增加,當HeaderView完全可見時達到最大值并且快遞員“取到”包裹,松開手后快遞員開始“拼命送貨”。
其中放大效果我是用ScaleDrawable實現,通過手指劃過的位移改變Drawable的level從而改變圖片的大小,不熟悉ScaleDrawable的可以參考Android Drawable之ScaleDrawable。松開手后快遞員奔跑是由幀動畫實現。
3.關鍵代碼
攔截部分:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float dy = event.getY() - mTouchY;
//當RecyclerView移到頂部并且手指向下滑動時,攔截事件,由自己處理Touch事件
if (dy > 0 && canPull)
return true;
case MotionEvent.ACTION_UP:
default:
break;
}
return false;
}
滑動部分:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dy = event.getY() - mTouchY;
mTouchY = event.getY();
if (Math.abs(mTouchY)<touchSlop)
break;
if (mCurrentStatus != STATUS_REFRESHING) {
//除以2是增加下拉的阻力感
headerLayoutParams.topMargin += dy / 2;
//此時為向上滑動到頭部完全隱藏的情況,繼續滑動的話應該交由RecyclerView處理了,故返回false自己不消耗事件。
if (headerLayoutParams.topMargin<=hideHeaderHeight){
headerLayoutParams.topMargin=hideHeaderHeight;
mHeaderView.requestLayout();
return false;
}
//此時為頭部完全顯示的情況
if (headerLayoutParams.topMargin>=0){
mCurrentStatus = STATUS_RELEASE_TO_REFRESH;
}else {
mCurrentStatus = STATUS_PULL_TO_REFRESH;
//改變圖片的大小及透明度
onLevelChanged((hideHeaderHeight-headerLayoutParams.topMargin)*100/hideHeaderHeight);
}
mHeaderView.requestLayout();
}
break;
case MotionEvent.ACTION_UP:
if (mCurrentStatus == STATUS_PULL_TO_REFRESH){
//屬性動畫實現平滑滾動
headerAnimation(headerLayoutParams.topMargin,hideHeaderHeight,350,null);
}else if (mCurrentStatus == STATUS_RELEASE_TO_REFRESH){
mCurrentStatus = STATUS_REFRESHING;
headerAnimation(headerLayoutParams.topMargin,0,250,null);
if (listener!=null)
listener.onRefresh();
}
break;
}
updateHeaderView();
lastStatus = mCurrentStatus;
return super.onTouchEvent(event);
}
<br />
具體代碼可以參考https://github.com/tangr2015/JDPullToRefresh
<br />
<br />