如果要用程式碼實現UIScrollView的滾動,我的第一反應就是寫一行類似這樣的程式碼:
1 |
[scrollView setContentOffset:CGPointMake(0, 100) animated:YES]; |
蘋果提供了這樣一個介面,表明它希望第三方程式設計師使用這個介面來完成UIScrollView的滾動操作。但是我一直在想,它和用UIView的property animation,來直接改變contentOffset有什麼不同呢?我為什麼不這樣寫呢:
1 2 3 4 |
[UIView animateWithDuration:0.25 animations:^{ [scrollView setContentOffset:CGPointMake(0, 100)]; }]; |
寫程式碼實驗了一下,發現這是兩種完全不同的滾動方式。
(1) 使用animated引數,可以獲得正確的UIScrollViewDelegate的回撥;而使用UIView動畫則不能。
在蘋果的官方文件中,對setContentOffset:animated:
這一方法會引起的回撥有大概如下的解釋:
如果animated這一引數設定為NO,或者直接設定contentOffset這個property,delegate會收到一個
scrollViewDidScroll:
訊息。如果animated這一引數設定為YES,則在整個動畫過程中,delegate會收到一系列的scrollViewDidScroll:
訊息,並且當動畫完成時,還會收到一個scrollViewDidEndScrollingAnimation:
訊息。
實驗證明,使用setContentOffset:animated:
方法得到的回撥行為和官方文件中描述的一致。而使用UIView動畫,則只能收到一次scrollViewDidScroll:
回撥,不能收到scrollViewDidEndScrollingAnimation:
回撥。
(2) 使用animated引數,可以獲取到動畫過程中contentOffset的值。
如果在動畫開始之前,contentOffset均為(0, 0),分別執行接下來的兩段程式碼:
1 2 3 4 5 |
[UIView animateWithDuration:0.25 animations:^{ [scrollView setContentOffset:CGPointMake(0, 100)]; }]; NSLog(@"%f", scrollView.contentOffset.y);//輸出:100.000000 |
1 2 3 4 5 |
[scrollView setContentOffset:CGPointMake(0, 100) animated:YES]; NSLog(@"%f", scrollView.contentOffset.y);//輸出:0.000000 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ NSLog(@"%f", scrollView.contentOffset.y);//輸出:25.500000,每次輸出不保證一致 }); |
可以看出,使用UIView動畫後,無論在什麼時候查詢contentOffset的值,得到的都是動畫的最終值。而使用animated引數,可以在動畫過程中得到與當前狀態較為一致的contentOffset值。
參考這篇文章,改變UIScrollView的contentOffset,實際上應該就是在改變UIScrollView的bounds。按照蘋果官方文件中的描述,bounds這個property是可以用作UIView動畫的property。
但是setContentOffset:animated:
這一方法中實現的肯定不是UIView一個property animation那麼簡單。
實際工作中,我也發現,在tableView中使用animated引數這種方法呈現的動畫效果的流暢程度明顯低於UIView動畫。但是考慮到UIScrollView的回撥和蘋果的推薦,還是應該儘量使用setContentOffset:animated:
這個介面來完成UIScrollView的滾動。