scrollView.contentView纔是其展現內容,對應的是contentSize,須要手動設置(相似frame)objective-c
在滑動時,實際改變的是scrollView.bounds.origin。瀏覽器
bounds是scrollView內部座標系,bounds
的origin
,至關於原點的座標值
。安全
拉列表,列表越長,contentOffset越大。 contentSize就是contentView的size。 contentSize、contentOffset和contentInset的圖解辨別bash
Banner於TableViewapp
adjustContentInset
,表示contentView.frame.origin偏移了scrollview.frame.origin多少;是系統計算得來的,計算方式由contentInsetAdjustmentBehavior
決定。計算規則較複雜,iOS 11 安全區域適配總結不但願上面Inset中自動修改,iOS11以前設置Controller的automaticallyAdjustsScrollViewInsets爲NO,iOS11以後動畫
if ([scrollview respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
scrollview.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
複製代碼
做爲controller.view
的第0個子視圖
時,會自動修改contentInset和scrollIndicatorInsets屬性,避免導航欄、TabBar的遮擋。ui
默認YES,即便用戶滑到了頭,仍是能夠滑(可用於下拉刷新等),會顯示背景色。spa
依賴於bounces=YES3d
默認NO,設置成YES,即便內容小於bounds,也能夠拉。代理
只能中止在bounds的倍數上,配合UIPageControl能夠實現輪播頁的效果
放縮用
狀態相關,拖曳、觸碰、減速狀態
refreshControl
iOS10UIRefreshControl
原理:經過-scrollViewDidScroll:代理方法,跟蹤contentOffset的的變化。不知足懸停條件時,hidden。
原理:
經過-scrollViewDidScroll:代理方法跟蹤contentOffset的的變化,根據contentOffset動態設置圖片的縮放比例
// 以"動態修改圖片縮放比例於1倍和2倍之間"爲例
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat scale = 1 - (scrollView.contentOffset.y / 100);
scale = (scale >= 1) ? scale : 1;
scale = (scale <= 2) ? scale : 2;
imageView.transform = CGAffineTransformMakeScale(scale, scale);
}
複製代碼
原理:
建立N+2個UIImageView
經過-scrollViewDidScroll:代理方法,跟蹤contentOffset的的變化
在滑動到首尾兩個圖片處,設置contentOffset到真實圖片處。
通常是用 childVC + UIPageViewController 實現
下面最後兩個與scrollview無關
利用拖曳位置: 開始位置 + 中止&中止滑動位置,contentOffset判斷
若是實時性要求高,能夠在didScroll裏面,按照時間間隔來判斷(基本不會用到)
TableView、CollectionView 利用beginDragging + willDisplayCell:的contentOffset判斷。
利用手勢
利用touchesBegan:、touchesMoved:、touchesEnded:
滾動
//contentOffset發生變化時調用(包括拖曳、減速過程、直接代碼設置)
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
複製代碼
手指相關,一次拖曳,只調用一次。
//1 將要開始拖拽頁面(非實時)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
//2 將要中止拖曳時(以velocity爲初速度,直到targetContentOffset中止。可經過修改targetContentOffset,調整位置)
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
//3 手指離開時,若是decelerate爲NO時,表示`滑動動畫結束`。
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;
//4 判斷中止動畫,要配合2或3,才完備
- (void)scrollViewWillEndDecelerating:(UIScrollView *)scrollView;
複製代碼
放縮
- (void)scrollViewDidZoom:(UIScrollView *)scrollView;
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; // return a view that will be scaled. if delegate returns nil, nothing happens
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view NS_AVAILABLE_IOS(3_2); // called before the scroll view begins zooming its content
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale;
複製代碼
狀態欄
// 當scrollView已經滑動到頂部時調用(僅當點擊狀態欄讓scrollView滑動到頂部才調用)
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;
複製代碼
// 當-setContentOffset:animated:/-scrollRectVisible:animated:方法動畫結束時調用(僅當animated設置爲YES時才調用)
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
複製代碼
用戶按下時,UIScrollView不知道用戶的意圖
在按下一瞬間,UIEvent傳遞完成後,不會馬上響應,而是開始一個150ms的倒計時,並監聽用戶接下來的行爲
倒計時結束前,手指發生移動,滾動contentView,優先識別爲手勢。
倒計時結束時,手指位置沒改變,調用-touchesShouldBegin:withEvent:inContentView: 詢問是否將事件的響應權交給子視圖(NO則不傳遞,YES則傳遞,默認YES)
事件傳遞給子視圖後,手指位置又發生了移動,調用-touchesShouldCancelInContentView:詢問是否取消已傳遞給子視圖的事件
這裏原文中寫的是,ScrollView會攔截UIEvent不傳給子視圖,根據經驗,若是ScrollView嵌套ScrollView,仍是子ScrollView先響應,所以,傳遞應該仍是會傳遞的,可是誰來響應,依據是手勢 & 響應鏈中說的,手勢>UIControl>UIResponder。
UIScrollView的詳細使用介紹和實現原理分析[2018.06.20更新]
只容許橫向:
設置subview的frameY與scrollView的frameY相等,而後設置alwaysBounceVertical=No(默認就是No)