你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 示例詳解:UIScrollview 與 Autolayout 的那點事

示例詳解:UIScrollview 與 Autolayout 的那點事

編輯:IOS開發基礎

1.jpg

前言

自從寫了介紹Masonry那篇文章以後 就一直有人對UIScrollView的那個例子不是很理解

UIView *container = [UIView new];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    make.width.equalTo(scrollView);
}];
  • 為什麼要用一個container包含其他subview?

  • 為什麼指定了edges 還要指定width? 不是多此一舉嗎?

那麼今天我就按照我的理解來說明一下這個問題

梳理

直入主題 要解釋之前的問題 最重要的一個概念就是

UIScrollView依靠與其subviews之間的約束來確定ContentSize的大小

換成代碼 是這個樣子

[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(v1.mas_left);
    make.right.equalTo(v1.mas_right);
    make.top.equalTo(v1.mas_top);
    make.bottom.equalTo(v1.mas_bottom);
}];

這是因為UIScrollView是個非常特殊的view UIScrollView與其subview之間相對位置的約束 並不會直接用於frame的計算 而是會轉化為對ContentSize的計算

換句話說 當UIScrollView知道了上下左右的約束分別指向subview什麼位置之後 只要subview的位置固定下來了 ContentSize的大小就確定下來了

下面來個簡單的例子 強烈建議配合demo來理解下面的例子(demo的鏈接在文尾)

請點擊->在線演示 (為了方便理解 我將ContentSize用紅線框了出來 另外為了查看ContentSize 我把UIScrollView的clipTobounds關閉了 可以通過左上角的開關來切換實際的效果)

示例1

[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    make.width.equalTo(scrollView);
    make.height.equalTo(scrollView).multipliedBy(1.5);
}];

效果

1.jpg

這裡我建立了一個寬等於scrollview 高等於scrollview高度1.5倍的view 然後scrollview成功的計算出了ContentSize

關鍵就在於

make.edges.equalTo(scrollView);

這句話其實等同與之前我提到的

[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(v1.mas_left);
    make.right.equalTo(v1.mas_right);
    make.top.equalTo(v1.mas_top);
    make.bottom.equalTo(v1.mas_bottom);
}];

scrollview因為上面的約束 會以v1的大小來計算ContentSize

示例2

如果嘗試改變v1的大小 會怎麼樣呢?

[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    
    make.size.equalTo(scrollView).sizeOffset(CGSizeMake(80, 80));
}];

效果

2.jpg

能看到 當我僅改變v1的大小 而不變其他的東西的情況下 scrollview的ContentSize也是隨著v1的大小變化而變化的

示例3

接下來示例就會稍微復雜點 如果同時有兩個view 會如何呢?

[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    
    make.left.top.right.equalTo(scrollView).insets(UIEdgeInsetsMake(10, 10, 0, 10));
    
    make.width.equalTo(scrollView).multipliedBy(1.1);
    make.bottom.equalTo(v2.mas_top).offset(-50);
    make.height.equalTo(@200);
}];
[v2 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.bottom.equalTo(scrollView);
    
    make.left.right.equalTo(v1).insets(UIEdgeInsetsMake(0, 50, 0, 50));
    make.height.equalTo(@250);
}];

效果

3.jpg

這個例子中 scrollview的四個方向的約束並沒有放在同一個subview上 而是分別指向了兩個view 所以scrollview的ContentSize會根據兩個view之間的約束來確定

示例4

如果將四個方向的約束分別放到四個不同的view上面 會怎麼樣呢?

CGSize size = CGSizeMake(200, 200);
[v1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerY.equalTo(scrollView.mas_top);
    
    make.size.mas_equalTo(size);
}];
[v2 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerX.equalTo(scrollView.mas_left);
    
    make.size.mas_equalTo(size);
    make.right.equalTo(v1.mas_left);
    make.top.equalTo(v1.mas_bottom);
}];
[v3 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerX.equalTo(scrollView.mas_right);
    
    make.size.mas_equalTo(size);
    make.left.equalTo(v1.mas_right);
    make.top.equalTo(v1.mas_bottom);
}];
[v4 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerY.equalTo(scrollView.mas_bottom);
    
    make.size.mas_equalTo(size);
    make.left.equalTo(v1.mas_left);
    make.top.equalTo(v2.mas_bottom);
}];

效果

2015-12-01-scrollview-under-autolayout4.jpg

將四個方向的約束分別指向四個view的中心點 我們也能得到正確的ContentSize

如果你看懂了示例4的代碼與效果 相信你對這個問題的所有疑惑都應該已經解除了

那麼再回到最開始那個問題

make.edges.equalTo(scrollView);
make.width.equalTo(scrollView);

一般情況下我們使用UIScrollView來進行autolayout布局 都是為了實現類似Android中的線性布局(有很多雜的非重復性的subview 如果使用UITableView和UICollectionView太麻煩) 這時直接使用UIScrollView就會很靈活

那麼

如果我們需要豎向的滑動 就把width設為和scrollview相同

如果需要橫向的滑動 就把height設為和scrollview相同

就是這麼簡單

小結

源碼和Demo請點這裡

前不久@nixzhu也寫了一篇關於UIScrollView的文章 然後我在微博上回復說使用一個單一的containerView占滿全部,然後把所有的subview添加到containerView中” 不過nixzh 表示他是極力避免這樣的 但是後在這個問題上 我是極力推薦這樣使用的

就如同示例1和示例2一樣 如果你需要添加subview 你只要簡單的添加到v1上 並添加與v1的約束 就可以獲得正確的ContentSize了

如果不這樣做 就類似示例3和示例4 這些邊界約束都需要一個一個的設置 這其實是沒有必要的

使用單一的containerView其實是這個問題上的最佳實踐


  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved