產(chǎn)品經(jīng)理說按照某團(tuán)、某東、某寶的效果實(shí)現(xiàn)。我X,我要是能一模一樣的實(shí)現(xiàn)別人的效果你覺得我還會(huì)待在這里嗎?
通常,需求確定下來,UI出圖之后看到稍微復(fù)雜的頁面后會(huì)先到簡(jiǎn)書、GitHub、cocoaChina上面去找有沒有。如果有直接照搬過來,如果沒有就有點(diǎn)懵逼了,為什么會(huì)這樣?還是基礎(chǔ)知識(shí)不扎實(shí),技術(shù)不夠呀!那該怎么辦?平常多思考、多積累唄,不要僅僅當(dāng)一個(gè)代碼搬運(yùn)工,沒有前途??!言歸正傳!
UIScrollView其實(shí)是沒有設(shè)置慣性這個(gè)屬性的,只能通過代理方法監(jiān)聽滾動(dòng)的過程,來達(dá)到控制慣性的目的。

首先要明確,通過[scrollView setContentOffset:CGPointZero animated:NO];這個(gè)方法設(shè)置UIScrollView的偏移,是不會(huì)觸發(fā)UIScrollView的- (void)scrollViewDidScroll:(UIScrollView*)scrollView這個(gè)代理方法的。
接下來看一下怎么通過UIScrollView的代理方法達(dá)到取消慣性
1、當(dāng)手指放在屏幕開始拖動(dòng)前,會(huì)先調(diào)用下面的代理方法
- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView {
? ? ? lastContentOffset = scrollView.contentOffset.y;//用來判斷滾動(dòng)方向
}
2、滾動(dòng)中會(huì)調(diào)用下面的代理方法
- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
//可以再這個(gè)方法里面動(dòng)態(tài)控制某個(gè)控件的隱藏、透明度以及跟隨UIScrollView的偏移而變化位置
? ? ? CGFloatoffsetY? = scrollView.contentOffset.y;
if (offsetY < self.lastContentOffset){//向下滾動(dòng)
? ? } else if (offsetY >self.lastContentOffset) {//向上滾動(dòng)
? ? }
}
3、這個(gè)是控制慣性滑動(dòng)的重要方法,手指將要松開時(shí)調(diào)用
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inoutCGPoint *)targetContentOffset
{
? ? CGFloat speed = fabs(velocity.y);//滾動(dòng)速度的絕對(duì)值,也可以根據(jù)velocity.y的正負(fù)判讀滾動(dòng)方向 假如為0 說明手動(dòng)拖動(dòng)停止 沒有慣性滑動(dòng)
? ? CGFloat offsetY = scrollView.contentOffset.y;
? ? CGFloat maxSpeed =2.7;//超過這個(gè)最大速度要做的操作
? ? if( velocity.y <0) {//向下滑動(dòng)
? ? ? ? if(speed > maxSpeed && offsetY >0) {//頂部往下滑
? ? ? ? ? ?[self performSelectorOnMainThread:@selector(stopOnTop:) withObject:scrollView waitUntilDone:NO];//一定要在主線程立即執(zhí)行 和 runLoop有關(guān)
? ? ? ? }
? ? }
? ? else {//向上滑動(dòng)
? ? }
}
- (void)stopOnTop:(UIScrollView *)scrollView {//在頂部停止?jié)L動(dòng)
? ? [self.tableView setContentOffset:CGPointZero animated:YES];
}
4、手指已經(jīng)松開會(huì)調(diào)用這個(gè)代理方法
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {//decelerate為YES 說明有滑動(dòng) NO沒有滑動(dòng) 直接停止
if (!decelerate) {//手指控制 直接停止 也就是拖動(dòng)一段距離直接停止
? ? ? ? BOOLdragToDragStop = scrollView.tracking && !scrollView.dragging && !scrollView.decelerating;
? ? ? ? if(dragToDragStop) {// 停止后要執(zhí)行的代碼
? ? ? ? ? ? [self scrollViewEndScroll:scrollView];
? ? ? ? }
? ? }
}
5、減速結(jié)束會(huì)調(diào)用這個(gè)方法,并不是就一定等于滑動(dòng)結(jié)束了。因?yàn)橛行┗瑒?dòng)并不需要減速也可以結(jié)束,比如我兩只手輪流向左滑動(dòng),直到滑動(dòng)到scrollview的右側(cè)盡頭為止,這個(gè)過程的滑動(dòng)是被迫終止而不是自然減速停止,這樣scrollViewDidEndDecelerating方法是不會(huì)被執(zhí)行的
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
BOOLscrollToScrollStop = !scrollView.tracking && !scrollView.dragging && !scrollView.decelerating;//為YES 表示滾動(dòng)結(jié)束
? ? if(scrollToScrollStop) {// 停止后要執(zhí)行的代碼
? ? ? [self scrollViewEndScroll:scrollView];
? ? }
}
- (void)scrollViewEndScroll:(UIScrollView *)scrollView { //完全停止?jié)L動(dòng)要做的處理
}

以上代理方法,只有真正理解后才能很好的處理跟ScrollView滾動(dòng)相關(guān)的事件!
下面補(bǔ)充一些小的知識(shí)點(diǎn)
self.tableView.decelerationRate = UIScrollViewDecelerationRateFast; ? ?//這個(gè)屬性用來調(diào)節(jié)scrollView的滾動(dòng)速度
? ? ?int abs(int i);? ? ? ? ? ? ? ? ? //處理int類型的取絕對(duì)值
?? ? double fabs(double i);//處理double類型的取絕對(duì)值
?? ? float fabsf(float i);? ? ? ? ? /處理float類型的取絕對(duì)值
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(- 104, 0, 0, 0);//設(shè)置滾動(dòng)條的偏移量,如果發(fā)現(xiàn)豎向滾動(dòng)條錯(cuò)亂,一般和scrollView的automaticallyAdjustsScrollViewInsets 屬性有關(guān),設(shè)置為NO即可
參考資料:
https://tech.glowing.com/cn/practice-in-uiscrollview/