代碼先行:https://github.com/CrazyPumPkin/DragMoreScrollView
有一天產(chǎn)品說某圖片列表瀏覽大圖要像iOS相冊(cè)那樣,于是便做了這么一個(gè)東西到忽,靜圖如上菇用,動(dòng)圖如下:
主要需求有以下幾點(diǎn):
- 上滑彈出詳情在扰,跟隨圖片底部滑動(dòng)焙格,松手整體運(yùn)動(dòng)至頂部瓮床,圖片露出固定大小
- 下滑圖片隨手指軌跡移動(dòng)并縮放芜茵,背景作透明度變化叙量,松手退出大圖瀏覽,且運(yùn)動(dòng)至原圖片列表的位置(其實(shí)就是微信看圖的那個(gè)效果)
- 在對(duì)圖片進(jìn)行放大縮小瀏覽的時(shí)候禁用上述兩個(gè)交互效果
可以看到問題在于九串,一開始是一張看起來是普通的帶縮放瀏覽功能的圖片绞佩,上滑便變成了一個(gè)圖文混搭的可上下滑動(dòng)的ScrollView寺鸥,從頭實(shí)現(xiàn)一個(gè)控件貌似不是很有必要,所以我們這里選擇繼承ScrollView
品山,讓它幫我們處理瀏覽詳情時(shí)的滑動(dòng)胆建。通讀一遍ScrollView
的onTouchEvent()
方法,可知它實(shí)現(xiàn)滑動(dòng)效果的關(guān)鍵代碼在下面這里:
ScrollView.java
public boolean onTouchEvent(MotionEvent ev) {
...
switch (actionMasked) {
...
case MotionEvent.ACTION_MOVE:
...
if (mIsBeingDragged) {
mLastMotionY = y - mScrollOffset[1];
final int oldY = mScrollY;
final int range = getScrollRange();
final int overscrollMode = getOverScrollMode();
boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
// 調(diào)用View的overScrollBy()方法肘交,該方法又調(diào)用了ScrollView重寫的onOverScrollBy()方法笆载,是實(shí)現(xiàn)滑動(dòng)效果的關(guān)鍵代碼
if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
&& !hasNestedScrollingParent()) {
mVelocityTracker.clear();
}
...
break;
...
return true;
}
}
protected void onOverScrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
//真正實(shí)現(xiàn)滑動(dòng)的地方
if (!mScroller.isFinished()) {
final int oldX = mScrollX;
final int oldY = mScrollY;
mScrollX = scrollX;
mScrollY = scrollY;
invalidateParentIfNeeded();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (clampedY) {
mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange());
}
} else {
super.scrollTo(scrollX, scrollY);
}
awakenScrollBars();
}
View.java
protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
...
onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
return clampedX || clampedY;
}
ok,知道了ScrollView的滑動(dòng)機(jī)制后涯呻,我們可以重寫它的onOverScrollBy
方法凉驻,當(dāng)處于瀏覽圖片狀態(tài)下時(shí),我們通過消費(fèi)掉該方法的deltaY
來攔截ScrollView的滑動(dòng)复罐,從而讓我們自己來掌控滑動(dòng)的效果(例如下滑退出大圖)涝登,當(dāng)上滑進(jìn)入詳情時(shí),我們又將滑動(dòng)交付給ScrollView自己去完成
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
if(想攔截滑動(dòng)事件){
handle(deltaY);
deltaY = 0;
}
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
大致思路就是如此效诅,實(shí)現(xiàn)起來也不難胀滚,代碼見Github,注釋里已寫得很清楚乱投。