1. 程式人生 > >ScrollView自動佈局技巧

ScrollView自動佈局技巧

scrollView自動佈局技巧

  • 步驟:
1. sb中拖scrollView
2. 設定scrollView上下左右為0
4. 拖一個UIView"yellowView"到scrollView中(不是imageView)
5. 設定yellowView的自動佈局上下左右為0(此時報錯,實際缺少尺寸"無法算出contentSize")
6. 設定yellowView和scrollView等寬等高
7. 更新frame,並執行
  • 此時無法滾動,因為contentSize和scrollView的size一樣大
8.設定yellowView寬約束的是scrollView寬的2倍,並執行
  • 此時 可以滾動了,因為yellowView的寬大於scrollView自身的寬
9. 設定yellowView頂部約束為64,並執行,會影響它的contentSize
10. 給yellowView上的新增按鈕,並設定約束,演示分頁屬性,並執行
  • 實驗小結:
1. 設定scrollView中內容的距離scrollView四邊邊距值,會影響contentSize即滾動範圍,上下間距
   會影響contentSize的Hieght"垂直滾動範圍",左右間距會影響水平滾動範圍(不常用,瞭解裝逼使用)
2. 如果用AutoLayout約束scrollView中的內容時只設置四邊間距約束是不夠的,還要設定view寬高
3. 
除了UIImageView可以不用直接設定寬高,因為它裡面如果設定了圖片,imageView的size會根據圖片 自適應,對應設定 scrollView的contentSize 4. 切記scrollView在實用自動佈局時比較特殊 5. 建議:如果一個scrollView中有很多小控制元件可以把小控制元件新增一個容器檢視 view,設定容器view的尺 寸為contentSize

scrollView-代理方法

  • scrollViewDidScroll: 滾動檢視滾動時使用
  • scrollViewDidEndDecelerating: 滾動檢視停止滾動時使用
  • viewForZoomingInScrollView: 縮放檢視時使用
  • 滾動相關方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSLog(@"%@", @"scrollview檢視開始滾動");
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
    NSLog(@"%@", @"將要減速 - 在釋放開手之後呼叫");
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    NSLog(@"%@", @"完成減速 - 完全靜止後呼叫");
}
  • 縮放相關方法

實現縮放的兩個步驟

  1. 需要設定最小縮放比例(minimumZoomScale)和最大縮放比例(maximumZoomScale)都為1時無法縮放
  2. 需要實現 “viewForZoomingInScrollView” 方法 告訴 scrollView 縮放的檢視

( 只要縮放就會呼叫 )

 // 告訴滾動檢視縮放的檢視
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return _imageView;
}


// @param scrollView 滾動檢視
// @param view       縮放的檢視
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {

    NSLog(@"%@", @"縮放開始時呼叫");
}


/// @param scrollView 滾動檢視
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
    NSLog(@"%@",@"正在縮放時呼叫");
}


/// @param scrollView 滾動檢視
/// @param view       縮放的檢視
/// @param scale      縮放的比例
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale {

    NSLog(@"%@",@" 縮放結束後呼叫");
}
  • 拖拽相關方法
/// @param scrollView 滾動檢視
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {

    NSLog(@"%@", @"將要開始拖拽");
}


/// @param scrollView          滾動檢視
/// @param velocity            速度
/// @param targetContentOffset 目標偏移位置
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {

    NSLog(@"%@", @"將要結束拖拽");
}


/// @param scrollView 滾動檢視
/// @param decelerate 是否減速
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {

    NSLog(@"%@ %d", @"完成拖拽方法,手指放開後呼叫", decelerate);
    }
  • 狀態列相關方法
結合 self.scrollView.scrollsToTop = YES;使用要告訴它點了狀態列對那個scrollView進行滾動
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {

    NSLog(@"%@", @"將要滾動到頂部,點選狀態列時呼叫");
    return YES;
}

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {

    NSLog(@"%@", @"已經滾動到狀態列");
}
  • 動畫相關方法
/**
 The scroll view calls this method at the end of its implementations of the setContentOffset:animated: and scrollRectToVisible:animated: methods, but only if animations are requested.

 滾動檢視會在實現了 setContentOffset:animated: & scrollRectToVisible:animated: 方法之後
 呼叫此方法

 同時必須在上述兩個方法中允許動畫
 */
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {

    NSLog(@"%@", @"呼叫動畫結束");
}

關於代理設計模式

  • 自己想幹一件事,但是自己不能主動完成/不能完成,要找一個物件幫自己完成
  • scrollView知道被滾動了,但是不知道被滾動以後將要做什麼

  • 手寫代理步驟

    • 找人做事情的人
      • 協議
      • 協議中的方法
      • 代理物件屬性
      • 在需要做事情的’時候’,通過代理物件,執行協議中的方法
    • 做事情的人
      • 遵守協議
      • 設定代理物件
      • 實現代理方法,在代理方法中做事情

ScrollView-屬性

  • contentSize: 內容大小,設定了才可以滾動
  • contentOffset: 內容偏移位置
  • contentInset: 內容間距
  • pagingEnabled: 是否允許分頁
  • bounces: 是否允許彈簧效果
  • showsHorizontalScrollIndicator: 是否允許顯示水平指示器(滾動條)
  • showsVerticalScrollIndicator: 是否允許顯示垂直指示器(滾動條)
  • 滾動內容屬性
// 內容偏移位置
@property(nonatomic)         CGPoint                      contentOffset;                  // default CGPointZero
// 內容大小,設定了才可以滾動
@property(nonatomic)         CGSize                       contentSize;                    // default CGSizeZero
// 內容間距
@property(nonatomic)         UIEdgeInsets                 contentInset;
  • 委託屬性
@property(nullable,nonatomic,weak) id<UIScrollViewDelegate>   delegate;
要想監聽滾動檢視的滾動 / 拖拽 / 縮放 / 狀態列互動

需要設定 delegate
實現相關協議方法
  • 彈簧效果屬性
// 允許彈簧效果
@property(nonatomic)   BOOL   bounces;                        // default YES. if YES, bounces past edge of content and back again
// 始終允許垂直彈
@property(nonatomic)   BOOL   alwaysBounceVertical;           // default NO. if YES and bounces is YES, even if content is smaller than bounds, allow drag vertically
// 始終允許水平彈
@property(nonatomic)   BOOL   alwaysBounceHorizontal;
  • 分頁屬性
// 允許分頁
@property(nonatomic,getter=isPagingEnabled) BOOL pagingEnabled __TVOS_PROHIBITED;// default NO. if YES, stop on multiples of view bounds
  • 指示器屬性
// 顯示水平指示器
@property(nonatomic)         BOOL                         showsHorizontalScrollIndicator; // default YES. show indicator while we are tracking. fades out after tracking
// 顯示垂直指示器
@property(nonatomic)         BOOL                         showsVerticalScrollIndicator;   // default YES. show indicator while we are tracking. fades out after tracking
// 指示器間距
@property(nonatomic)         UIEdgeInsets                 scrollIndicatorInsets;          // default is UIEdgeInsetsZero. adjust indicators inside of insets
// 指示器樣式
@property(nonatomic)         UIScrollViewIndicatorStyle   indicatorStyle;                 // default is UIScrollViewIndicatorStyleDefault
在 scrollView 中指示器本質上就是 UIImageView

通過檢視檢視層次結構可以看到
  • 縮放屬性
// 最小縮放比例
@property(nonatomic) CGFloat minimumZoomScale;     // default is 1.0
// 最大縮放比例
@property(nonatomic) CGFloat maximumZoomScale;     // default is 1.0. must be > minimum zoom scale to enable zooming
要允許縮放

必須設定以上兩個屬性
同時遵守協議
實現協議方法 -viewForZoomingInScrollView:
  • 狀態列屬性
// 點選狀態列滾動到頂部
// default is YES. TVOS上此屬性禁用,
@property(nonatomic) BOOL  scrollsToTop __TVOS_PROHIBITED;          
一個檢視中,如果有多個 scrollView
只有唯一一個 scrollView 的 scrollsToTop 屬性設定為 YES,才支援點選狀態列滾動到頂部
雖然此屬性預設值即為YES不過還要要設定,不然不知道點了狀態列要對那個scrollView進行滾動
  • 鍵盤屬性
// 鍵盤解除模式
@property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode NS_AVAILABLE_IOS(7_0); // default is UIScrollViewKeyboardDismissModeNone
如果是 UITextView,通常需要將 alwaysBounceVertical 屬性設定為 YES

typedef NS_ENUM(NSInteger, UIScrollViewKeyboardDismissMode) {
    // 無
    UIScrollViewKeyboardDismissModeNone,
    // 拖拽關閉鍵盤
    UIScrollViewKeyboardDismissModeOnDrag,      // dismisses the keyboard when a drag begins
    // 必須要拖拽到鍵盤才可以關閉鍵盤,很少使用
    UIScrollViewKeyboardDismissModeInteractive, // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
} NS_ENUM_AVAILABLE_IOS(7_0);
  • 常用方法
// 動畫設定偏移位置
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;  // animate at constant velocity to new offset

// 動畫設定滾動區域
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;         // scroll so rect is just visible (nearest edges). nothing if rect completely visible
  • 三種影象填充模式
- scale的意思是:縮放,在contentMode中出現的話,就是要改變圖形的大小了。
- aspect的意思是縱橫的比例,在contentMode中的意思是保持圖形的縱橫比,保持圖片不變形。

scale to fill:縮放圖片,使圖片充滿容器。因為沒有aspect,所以是不保持縱橫比的。圖片不是按比例縮放的。
scale aspect fit: 在保持縱橫比(aspect)的前提下,縮放圖片(scale),使圖片在容器內都顯示出來(fit)。
    保證圖片完整顯示,但不保證能充滿容器。
scale aspect fill:在保持縱橫比(aspect)的前提下,縮放圖片(scale),使圖片充滿容器(fill)。保證圖片能
    充滿容器,不保證圖片能完整顯示。

新特性檢視規則

新特性檢視

  • 自動佈局的選擇?
    • 如果是全屏的直接bounds,如果不是考慮使用自動佈局
  • 並不是每次都需要現實新特性介面,所以留個後路,以後再改
  • 建立控制元件時呼叫init或initWithFrame方法最後都會去呼叫物件父類的initWithFrame方法

隱藏狀態列

  • 隱藏狀態來這些不屬於顯示也不屬於資料,所以應該再C中找.
  • -(BOOL)prefersStatusBarHidden

傳遞資料思路對比

  • View直接寫資料?(1)
  • 控制器傳遞給View?(2)
  • 可能面臨到檢視移植的問題,也就說,如果我另外一個專案也需要同樣的需求,那麼:
    • 如果使用第一種方式,需要做的工作.
      • 拷貝檔案,更改view內部中的圖片名稱.
    • 如果使用第二種方式,需要做的工作.
      • 拷貝檔案,在控制器重新寫資料,傳入view.
  • 檢視只負責現實,控制器負責排程.
  • 兩種方式,沒有對不對,只有合不合適.

將新特性陣列傳遞給新特性

  • 新建一個裝滿imageName的陣列傳遞給檢視

設定scrollView的frame

  • 建立scrollView並設定frame
ZFBGuideView *guideView = [[ZFBGuideView alloc] initWithFrame:self.view.bounds];
ZFBGuideView *guideView = [[ZFBGuideView alloc] init];
guideView.frame = self.view.bounds;
  • 兩種寫法都會呼叫initWithFrame
  • 重寫了initWithFrame並且同時重寫了init的方法,第一種形式的方法不會再呼叫init
  • 設定子控制元件的frame應該使用layoutSubviews
  • layoutSubviews一定要重寫父方法
  • 約束的程式碼不能寫在layoutSubviews方法中,此方法會多次呼叫

scrollView顯示圖片並設定屬性

  • setImageNames方法中新增imageView到scrollView中
  • 並且設定影象和contentSize
  • 分頁
  • 水平和垂直指示器(方便使用subviews)
  • 禁用彈性

設定更多按鈕的自動佈局

  • 新增到imageView上
  • 開啟使用者互動
  • userInteractionEnabled(bool)

新增按鈕監聽/新特性移除動畫

  • 通過transform和透明度做動畫
  • 移除整個新特性檢視

使用程式碼建立pageControl

  • 應該新增到新特性檢視上,如果新增到scrollView上會跟著滾動
  • 禁用分頁的使用者互動

pageControl位置/設定總頁數

  • 自動佈局設定pageControl位置
  • 總頁數應該根據圖片數量來,所以寫在setImageNames方法中

設定pageControl當前頁數

  • 結束滾動的代理方法中,根據offset和scrollView的寬度進行計算
  • 或者
  • 正在滾動的代理方法中,根據offset和scrollView的寬度進行計算(加0.4999再強轉)

拖拽細節/隱藏pageControl

  • 需求的最右可以拖拽,思考怎麼樣增加?
  • 根據頁數進行pageControl的隱藏和現實.