NSLayoutConstraint (VLF) + ScrollView

在平時(shí)開(kāi)發(fā)中ScrollView扮演非常重要的角色贮缅,經(jīng)常需要給ScrollView添加一些ContentViews, 并能上下左右滑動(dòng)篇梭, 但是當(dāng)你添加完這些ContentViews,并設(shè)置好約束之后,驚訝的發(fā)現(xiàn)ScrollView上沒(méi)有任何內(nèi)容或ScrollView并不能滑動(dòng)。一陣驚慌中,瘋狂開(kāi)啟NSLog模式玩敏,茫然發(fā)現(xiàn)frame為0,contentSize為0质礼,什么情況旺聚?

導(dǎo)致這種現(xiàn)象的原因不是我們的約束設(shè)置有問(wèn)題,而是在AutoLayout模式下ScrollView計(jì)算ContentSize的機(jī)制不一樣的眶蕉,ContentSize是依據(jù)ContentViews的寬和高自動(dòng)計(jì)算出來(lái)的砰粹,不需要我們手動(dòng)設(shè)置。在ViewDidLoad之后造挽,系統(tǒng)會(huì)根據(jù)ContentViews情況重新算出ScrollView的ContentSize碱璃。

我們?cè)谔砑覵crollView時(shí),只是給出了到屏幕各個(gè)邊的約束為0饭入,卻沒(méi)有給出具體的寬度和高度嵌器, 所以無(wú)法確定ContentSize大小,自然不能滑動(dòng)谐丢。建議在ScrollView上先添加一個(gè)UIView爽航,UIView的大小和ScrollView一樣,然后在UIView上添加ContentViews, 這樣系統(tǒng)就會(huì)準(zhǔn)確的算出ScrollView的ContentSize, 保證ScrollView能滑動(dòng)起來(lái)乾忱。

NSLayoutConstraint有兩個(gè)添加constraint的方法:

+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *, id> *)views;

+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

WithVisualFormat方法比WithItem更加形象化讥珍、簡(jiǎn)潔化,建議多使用可視化方法饭耳。

在給ScrollView添加子視圖之前串述,建議先弄清楚ScrollView上一共有多少個(gè)子視圖执解,并使用可視化方法一并寫(xiě)出來(lái)寞肖,告訴系統(tǒng)我需要添加這些視圖纲酗,等之后這些視圖的尺寸確定下來(lái)后,你就可以計(jì)算contentSize了新蟆。否則觅赊,系統(tǒng)不知道你一共有多少個(gè)子視圖,也不知道第一個(gè)和最后一個(gè)子視圖是誰(shuí)琼稻,這樣就難以計(jì)算contentSize吮螺。

我現(xiàn)在需要在ScrollView上添加一個(gè)UIImageView,一個(gè)UIView, 一個(gè)UILabel帕翻。
在屏幕中位置如下:
ScrollView:
scrollView大小為屏幕大小鸠补,背景色white
ContentView:
contentView大小同scrollView大小,背后色red
UIImageView:
. top 距離底部60,
. left 距離左邊5
. right 距離右邊5
. height 高度100
背景色green
UIView:
. top 距離上面10
. left 距離左邊10
. right 距離右邊10
. height 高度80
背景色purple
UILabel:
. top 距離上面8
. left 距離左邊8
. right 距離右邊8
. height 高度根據(jù)文字內(nèi)容自動(dòng)調(diào)整
背景色yellow
效果圖如下:

screenShot.png

給ScrollView和ContentView添加約束的代碼如下:

    self.automaticallyAdjustsScrollViewInsets = NO;
    UIScrollView *scView = [[UIScrollView alloc] init];
    scView.backgroundColor = [UIColor whiteColor];
    scView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:scView];
    
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[scView]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(scView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[scView]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(scView)]];
    
    
    UIView *contentView = [[UIView alloc] init];
    contentView.backgroundColor = [UIColor redColor];
    contentView.translatesAutoresizingMaskIntoConstraints = NO;
    [scView addSubview:contentView];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[contentView]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[contentView]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];

注意:由于ScrollView可以垂直和水平滑動(dòng)嘀掸,所以我們指定ContentView的寬度為屏幕寬度后紫岩,scrollView就只能垂直滑動(dòng)了。

在添加子試圖之前需要一次性將所有的子視圖列舉出來(lái)睬塌,并設(shè)置好子視圖之間的上下間距

    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.backgroundColor = [UIColor greenColor];
    imageView.translatesAutoresizingMaskIntoConstraints = NO;
    [contentView addSubview:imageView];
    
    UIView *boxView = [[UIView alloc] init];
    boxView.translatesAutoresizingMaskIntoConstraints = NO;
    boxView.backgroundColor = [UIColor purpleColor];
    [contentView addSubview:boxView];
    
    UILabel *label = [[UILabel alloc] init];
    label.backgroundColor = [UIColor yellowColor];
    label.translatesAutoresizingMaskIntoConstraints = NO;
    [contentView addSubview:label];
    label.text = @"起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字起個(gè)很長(zhǎng)很長(zhǎng)的名字";
    label.numberOfLines = 0;
    [contentView addSubview:label];
    
    NSDictionary *tmpViewsDictionary = @{@"imageView":imageView,
                                         @"boxView":boxView,
                                         @"label":label,
                                         };
    
     [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(60)-[imageView(100)]-(10)-[boxView(80)]-(8)-[label]-(8)-|" options:0 metrics:nil views:tmpViewsDictionary]];
    
    [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(5)-[imageView]-(5)-|" options:0 metrics:nil views:tmpViewsDictionary]];
    [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[boxView]-(10)-|" options:0 metrics:nil views:tmpViewsDictionary]];
    [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(8)-[label]-(8)-|" options:0 metrics:nil views:tmpViewsDictionary]];

注意:需要時(shí)刻提醒自己準(zhǔn)確的指出每個(gè)子視圖的寬和高泉蝌,這樣ScrollView才能算出ContentSize。UILabel由于會(huì)根據(jù)text內(nèi)容自動(dòng)算出高度揩晴,所以不需要明確列出label的高度勋陪,而UIView如果不給出其高度的話,是無(wú)法正確顯示的硫兰。

最后如果我們將boxView的高度改的足夠高诅愚,如800,就可以看見(jiàn)ScrollView能像預(yù)期的那樣滑動(dòng)起來(lái)了

[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(60)-[imageView(100)]-(10)-[boxView(800)]-(8)-[label]-(8)-|" options:0 metrics:nil views:tmpViewsDictionary]];

最后吐槽下:NSLayoutConstraint真的很難用劫映。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呻粹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子苏研,更是在濱河造成了極大的恐慌等浊,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摹蘑,死亡現(xiàn)場(chǎng)離奇詭異筹燕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)衅鹿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門撒踪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人大渤,你說(shuō)我怎么就攤上這事制妄。” “怎么了泵三?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵耕捞,是天一觀的道長(zhǎng)衔掸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)俺抽,這世上最難降的妖魔是什么敞映? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮磷斧,結(jié)果婚禮上振愿,老公的妹妹穿的比我還像新娘。我一直安慰自己弛饭,他們只是感情好冕末,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著侣颂,像睡著了一般栓霜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上横蜒,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天胳蛮,我揣著相機(jī)與錄音,去河邊找鬼丛晌。 笑死仅炊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的澎蛛。 我是一名探鬼主播抚垄,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼谋逻!你這毒婦竟也來(lái)了呆馁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤毁兆,失蹤者是張志新(化名)和其女友劉穎浙滤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體气堕,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纺腊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茎芭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揖膜。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梅桩,靈堂內(nèi)的尸體忽然破棺而出壹粟,到底是詐尸還是另有隱情,我是刑警寧澤宿百,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布趁仙,位于F島的核電站洪添,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏幸撕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一外臂、第九天 我趴在偏房一處隱蔽的房頂上張望坐儿。 院中可真熱鬧,春花似錦宋光、人聲如沸貌矿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逛漫。三九已至,卻和暖如春赘艳,著一層夾襖步出監(jiān)牢的瞬間酌毡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工蕾管, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枷踏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓掰曾,卻偏偏與公主長(zhǎng)得像旭蠕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旷坦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)掏熬、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,059評(píng)論 4 62
  • 今天土土心情好漱办,來(lái)首歌吧这刷! 歌詞如下: “一點(diǎn)飛上天,黃河兩道彎娩井; 八字大張口暇屋,言字往里走, 你一扭洞辣,我一扭咐刨; 你...
    鄉(xiāng)土生活匯閱讀 526評(píng)論 0 0
  • 天天有網(wǎng)球團(tuán)隊(duì)培訓(xùn)課后匯總 ### 最新更新(更新至7月23日): ==++分級(jí)培訓(xùn)課程-各項(xiàng)技術(shù)要領(lǐng)匯總j夹啤!定鸟!+...
    bjpopeye閱讀 1,573評(píng)論 0 0
  • 傷感的歌曲總是能把自己帶入其中而涉。聽(tīng)了周杰倫的你好嗎,也許在不同時(shí)空联予,我還牽著你的手啼县。誰(shuí)能想到,我現(xiàn)在會(huì)以這種形式想...
    二十一加七閱讀 173評(píng)論 0 0
  • 1沸久、晚飯后季眷,東東在客廳看電視(規(guī)定周末可以看),我看有一段時(shí)間了卷胯,于是我說(shuō):“東東子刮,請(qǐng)你過(guò)來(lái)下”,然后告訴他窑睁,長(zhǎng)針...
    dhyh閱讀 242評(píng)論 0 0