圖文詳解ScrollView子控制元件約束新增

賣報的小畫家Sure發表於2017-07-18

前言
在iOS開發中,隨著iOS裝置的螢幕尺寸不斷更新,對於控制元件約束的新增極為重要。一些常用控制元件的約束新增在這裡不在贅述,本文主要詳細講解UIScrollView的約束新增。在本文中將以兩種方式進行實現,一種為系統的AutoLayout,另一種為藉助Masonry庫檔案。

首先我們在storyboard或xib檔案中拖入一個ScrollView,為其新增距邊緣均為0的約束,即使其充滿螢幕。

螢幕快照1
螢幕快照1

對於ScrollView的使用,我們可知的是需要為其設定兩大重要屬性,一為frame二為contentSize。frame用於確定其座標位置,contentSize用於確定其可滾動的區域。

上一步我們已經為ScrollView確定好了其座標位置即frame,接下來我們設定其可滾動的區域。但ScrollView在storyboard或xib中並不可以設定其contentSize,因此我們繼續拖入一個View作為ScrollView的子檢視,大家可認為此View為ScrollView的contentView,使用其來控制ScrollView的滾動區域

螢幕快照2
螢幕快照2

contentView作為ScrollView的子檢視,設定其約束為距ScrollView邊緣為0,約束新增好後發現出現了約束報錯,下步我們加以解決。

螢幕快照3
螢幕快照3

在解決約束報錯之前我們需要考慮當前ScrollView的滾動方式
若希望ScrollView橫向滾動,我們勾線如圖Vertically in Container選項,即豎直居中;若希望豎向滾動,我們勾選如圖Horizontally in Container選項;若希望ScrollView橫向豎向均可滾動,則無需勾選任何選項,跳過此部即可。

螢幕快照 4
螢幕快照 4

以橫向滾動為例,高度無須操作,需要限制contentView的寬度,例如將其設定為當前螢幕寬的兩倍

螢幕快照5
螢幕快照5

簡單為contentView設定個顏色,執行專案,我們即可發現我們生成了一個可滾動的ScrollView,其frame為(0,0,self.view.bounds.size.width,self.view.bounds.size.height),contentSize為(self.view.bounds.size.width*2,self.view.bounds.size.height)

效果圖.gif
效果圖.gif

對於contentSize我們也可以手動設定,可將contentView的寬度約束拖入程式碼進行更改

約束拖動.gif
約束拖動.gif

例如我們在程式碼中重新設定其約束

_widthLayout.constant = [UIScreen mainScreen].bounds.size.width * 5;複製程式碼

當前ScrollView可滾動區域橫向即變成了5倍螢幕的大小。

接下來我們為ScrollView設定子檢視。

為了顯示效果較好,我們設定UIImageView作為ScrollView子檢視,首先放置第一個ImageView,設定約束為左上下邊緣約束均為0。

螢幕快照6
螢幕快照6

繼續放置第二個ImageView,這隻約束為上下左右約束均為0

螢幕快照7
螢幕快照7

最後我們選中兩個ImageView,設定其等寬等高。

螢幕快照8
螢幕快照8

執行當前專案,即可實現如下效果

最終效果圖.gif
最終效果圖.gif

最後放下層級關係方便大家理解

螢幕快照9
螢幕快照9

使用系統的AutoLayout為UIScrollView新增約束就告一段落,在真實的開發中,使用ScrollView通常是製作廣告展示位。而廣告位的圖片個數是動態不固定的,因此通過storyboard或xib無法實現需求中的動態新增。我們通常是For迴圈建立指定數量的圖片(子檢視),這就需要我們通過程式碼手動為子檢視新增約束。

具體實現原理與AutoLayout的約束新增一致,詳細見程式碼,這裡使用Masonry庫檔案新增約束,摘取部分約束程式碼如下:

[_scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.mas_equalTo(self);
}];
[_contentView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.mas_equalTo(_scrollView);
    make.centerY.equalTo(_scrollView.mas_centerY).offset(0);
    make.width.equalTo(@(self.bounds.size.width * _imageArr.count));
}];

CGFloat space = 0;
//用於接收上一控制元件
UIImageView *lastImageView;
for (NSInteger i = 0; i < _imageArr.count; i++) {
    UIImageView *imageView = [self viewWithTag:1000 + i];
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(_contentView.mas_top).offset(space);
        make.bottom.equalTo(_contentView.mas_bottom).offset(space);
        if (lastImageView) {
            //如果存在上一控制元件,設定與上一控制元件右邊緣約束,設定等寬
            make.left.equalTo(lastImageView.mas_right).offset(space);
            make.width.equalTo(lastImageView.mas_width);
        } else {
            //不存在上一控制元件,設定與父檢視左邊緣約束,設定寬度為當前檢視寬度
            make.left.equalTo(_contentView.mas_left).offset(space);
            make.width.equalTo(@(self.bounds.size.width));
        }
        if (i == _imageArr.count - 1) {
            //若為最後一個控制元件,設定與父檢視右邊緣約束
            make.right.equalTo(_contentView.mas_right).offset(space);
        }
    }];
    //接收上一控制元件
    lastImageView = imageView;
}複製程式碼

呼叫方式如下

SureAutoLayoutScrollView *scrollView = [[SureAutoLayoutScrollView alloc]init];
scrollView.imageArr = @[@"IMG_1018.JPG",@"IMG_0857.JPG",@"IMG_0856.JPG"];
[self.view addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.mas_equalTo(self.view);
}];複製程式碼

具體邏輯已註釋標明,完整程式碼已上傳GitHub
Masonry版:github.com/LSure/SureA…
AutoLayout版:github.com/LSure/SureS…

簡書地址:www.jianshu.com/u/57d9688d4…

相關文章