本文提供 Demo下載
在iOS 11開始,從最早的地圖應用到最近的捷徑,陸續有系統應用使用從下方滑出列表的形式,這種系統提供的圓角風格視圖用手勢划出和隱藏時非常自然流暢。國內的一些應用也跟進了這種交互方式,但是我發現很大一部分APP都沒有正確的處理ScrollView滾動和視圖滾動的銜接,以至於相比於系統應用不夠自然。比如知乎、抖音的評論列表頁,需要手指拿開一下才能切換視圖移動和scroll滾動,銜接不夠連續。
此文沒什么技術含量,只提供了一種處理技巧正確處理類似這種嵌套滾動時響應對象的切換,讓你的應用和系統應用一樣自然流暢。我更多的目的是一種吶喊,希望國內這些常用app能夠注意到這些使用細節。

(系統應用的滑出視圖)

(Demo跑出來的效果,壓縮了分辨率,保留原始幀率)
因為此場景下有2種滑動,一種是視圖向上移動ScrollView不滾動,另一種模式是ScrollView滑動而視圖不移動,我們可能很自然的想到另外添加一個手勢,禁止ScrollView滾動,然后再去驅動視圖向上移動,在不需要的時候再去禁止這個手勢和開啟ScrollView滾動。如果這么處理,可能就會發現永遠也得不到一個銜接自然的滾動體驗。
我的方法是不要禁止ScrollView的手勢,但是可以取消ScrollView滾動:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
scrollView.contentOffset = CGPointMake(0, 0);
}
另外如果你理解了ScrollView的實現,那么就不用再另外添加手勢了,因為本身ScrollView也是由手勢驅動的,而我們可以直接得到scrollView.panGestureRecognizer:
[scrollView.panGestureRecognizer addTarget:self action:@selector(panGestureHandle:)];
大部分事物處理就將交給panGestureHandle處理了:
// 核心函數:手勢處理
- (void)panGestureHandle:(UIPanGestureRecognizer *)tap {
static CGPoint startPoint;
static CGPoint viewPoint;
static BOOL isBegan;
CGPoint endPoint;
if ((self.tableView.contentOffset.y > 0 && self.sizeState == SlideScrollViewStateFull)
|| self.top < FULL_TOP) {
isBegan = NO;
[self panGestureEndWithViewPoint:viewPoint];
return;
}
_scrollDecelerat = NO;
self.tableView.showsVerticalScrollIndicator = NO;
if (tap.state == UIGestureRecognizerStateBegan || isBegan == NO) {
isBegan = YES;
startPoint = [tap locationInView:self.superview];
viewPoint = self.origin;
}
switch (tap.state) {
case UIGestureRecognizerStateChanged: {
endPoint = [tap locationInView:self.superview];
CGFloat toPointY = viewPoint.y + (endPoint.y - startPoint.y);
self.top = toPointY;
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed: {
isBegan = NO;
[self panGestureEndWithViewPoint:viewPoint];
}
default:
break;
}
}
這里有需要注意的地方就是我們需要手動計算一次手勢移動的距離,因為一個手勢可能前一部分在響應ScrollView的滾動,而后一部分又切換到了移動視圖,所以開始移動的點可能並不是手勢開始的時候。
如果還有非ScrollView區域,這時候就可以另外添加一個手勢到這個區域視圖上了,如demo中的搜索框部分,處理函數和上面一樣即可。
有更多細節比如使ScrollView取消慣性滾動等,可以馬上查看Demo了解,這里就不一一列舉了。
