UIScrollView 小結

1 ScrollView實質

  1. scrollView.contentView纔是其展現內容,對應的是contentSize,須要手動設置(相似frame)objective-c

  2. 在滑動時,實際改變的是scrollView.bounds.origin。瀏覽器

bounds是scrollView內部座標系,boundsorigin,至關於原點的座標值安全

2 contentOffset

拉列表,列表越長,contentOffset越大。 contentSize就是contentView的size。 contentSize、contentOffset和contentInset的圖解辨別bash

Banner於TableViewapp

  • 能夠放在Header中
  • 也能夠做爲子控件,而後設置contentOffset.y=-50。

3 一些屬性

3.1 自動安全區域偏移相關

  • adjustContentInset,表示contentView.frame.origin偏移了scrollview.frame.origin多少;是系統計算得來的,計算方式由contentInsetAdjustmentBehavior決定。計算規則較複雜,iOS 11 安全區域適配總結

不但願上面Inset中自動修改,iOS11以前設置Controller的automaticallyAdjustsScrollViewInsets爲NO,iOS11以後動畫

if ([scrollview respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {

   scrollview.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

}

複製代碼
  • contentInset、scrollIndicatorInsets

做爲controller.view第0個子視圖時,會自動修改contentInset和scrollIndicatorInsets屬性,避免導航欄、TabBar的遮擋。ui

3.2 其餘

  • bounces

默認YES,即便用戶滑到了頭,仍是能夠滑(可用於下拉刷新等),會顯示背景色。spa

  • alwaysBounceVertical

依賴於bounces=YES3d

默認NO,設置成YES,即便內容小於bounds,也能夠拉。代理

  • pagingEnabled

只能中止在bounds的倍數上,配合UIPageControl能夠實現輪播頁的效果

  • zoomScale相關

放縮用

  • dragging, tracking, decelerating

狀態相關,拖曳、觸碰、減速狀態

3.3 refreshControl iOS10

UIRefreshControl

4 一些應用

4.1 懸停控件

原理:經過-scrollViewDidScroll:代理方法,跟蹤contentOffset的的變化。不知足懸停條件時,hidden。

4.2 頭部圖片下拉放大

原理:

經過-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);
}
複製代碼

4.3 無限輪播

原理:

建立N+2個UIImageView

經過-scrollViewDidScroll:代理方法,跟蹤contentOffset的的變化

在滑動到首尾兩個圖片處,設置contentOffset到真實圖片處。

4.4 圖片瀏覽器+圖片放縮功能

通常是用 childVC + UIPageViewController 實現

4.5 滑動方向判斷

下面最後兩個與scrollview無關

  1. 利用拖曳位置: 開始位置 + 中止&中止滑動位置,contentOffset判斷

  2. 若是實時性要求高,能夠在didScroll裏面,按照時間間隔來判斷(基本不會用到)

  3. TableView、CollectionView 利用beginDragging + willDisplayCell:的contentOffset判斷。

  4. 利用手勢

  5. 利用touchesBegan:、touchesMoved:、touchesEnded:

5 經常使用代理方法

滾動

//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;

複製代碼

6 其餘值得注意的地方

UIScrollView處理觸摸事件原理

用戶按下時,UIScrollView不知道用戶的意圖

在按下一瞬間,UIEvent傳遞完成後,不會馬上響應,而是開始一個150ms的倒計時,並監聽用戶接下來的行爲

  • 倒計時結束前,手指發生移動,滾動contentView,優先識別爲手勢。

  • 倒計時結束時,手指位置沒改變,調用-touchesShouldBegin:withEvent:inContentView: 詢問是否將事件的響應權交給子視圖(NO則不傳遞,YES則傳遞,默認YES)

  • 事件傳遞給子視圖後,手指位置又發生了移動,調用-touchesShouldCancelInContentView:詢問是否取消已傳遞給子視圖的事件

這裏原文中寫的是,ScrollView會攔截UIEvent不傳給子視圖,根據經驗,若是ScrollView嵌套ScrollView,仍是子ScrollView先響應,所以,傳遞應該仍是會傳遞的,可是誰來響應,依據是手勢 & 響應鏈中說的,手勢>UIControl>UIResponder。

UIScrollView的詳細使用介紹和實現原理分析[2018.06.20更新]

UIScrollView實戰經驗

只能橫向/縱向滑動

只容許橫向:

設置subview的frameY與scrollView的frameY相等,而後設置alwaysBounceVertical=No(默認就是No)

相關文章
相關標籤/搜索