UIStackView使用進(jìn)階

該文章屬于劉小壯原創(chuàng)鞍帝,轉(zhuǎn)載請注明:劉小壯


配圖

技術(shù)背景

前端的布局方式比較靈活,提供有Flex的布局方式胎围,可以實(shí)現(xiàn)不同方向的彈性布局。Flex就像一個容器壹粟,可以將其內(nèi)部的子控件統(tǒng)一進(jìn)行布局愕乎。其包含主軸方向和交叉軸方向,主軸方向表示控件的排布方向备禀,交叉軸方向和主軸方向相垂直洲拇。熟悉前端Flex控件的同學(xué)應(yīng)該知道。Flex有一些常用屬性曲尸,這里對其進(jìn)行簡單介紹赋续,方便了解UIStackView的技術(shù)背景。

  • flex-direction:控制Flex的方向另患,`垂直還是水平纽乱;
  • flex-wrap:是否允許換行顯示,nowrap表示單行顯示昆箕,nowarp的場景下鸦列,如果控件過多,則可能導(dǎo)致子項(xiàng)等比縮小的問題为严;
  • justify-content:決定Flex主軸方向上敛熬,子項(xiàng)對齊和分布方式,例如從前到后排列第股,或者等間距分布等应民;
  • align-items:決定Flex交叉軸方向上,子項(xiàng)的對齊和分布方式夕吻,例如主軸設(shè)置為row诲锹,交叉軸flex-start就表示頂對齊,center表示垂直居中對齊涉馅;
  • align-content:作用于交叉軸方向每行的對齊方式归园,屬性只針對于有換行的場景下有效。例如flex-start是從上到下逐行排列稚矿,space-between則表示每行間距相同庸诱,平均分配每行之間間距捻浦。

UIStackView介紹

在介紹完Flex布局的背景之后,這里講一下UIStackView控件桥爽。在iOS9中蘋果在UIKit框架中引入了一個新的視圖類UIStackView朱灿,UIStackView借鑒了Flex的布局思想,采用線性布局的方式钠四,統(tǒng)一對子視圖進(jìn)行布局盗扒。只需要寫很少的Masonry布局代碼,或者不寫布局代碼即可完成布局缀去。

UIStackView已經(jīng)推出有一些年了侣灶,這里介紹這個控件,主要是出于兩個目的缕碎。一方面是對于沒使用過的同學(xué)褥影,介紹這個控件的功能以及適用的場景,項(xiàng)目中的一些場景通過UIStackView處理起來會輕松很多阎曹。另一方面對于已經(jīng)使用過的同學(xué)伪阶,我會在文章中講一些我踩過的坑,以幫助大家更好的使用這個控件來解決業(yè)務(wù)中的問題处嫌。

需要注意的是栅贴,UIStackView雖然繼承自UIView,但是并不參與屏幕的渲染熏迹,所以重寫drawRect:方法也是無效的檐薯。

核心參數(shù)

UIStackView提供了兩個方向的布局,垂直布局和水平布局注暗,我們可以通過UILayoutConstraintAxis枚舉值進(jìn)行設(shè)置坛缕。如果初學(xué)者來學(xué)習(xí)UIStackView比較抽象,不太好接觸這個新的控件捆昏,而且很容易出錯赚楚,先看一下下面這個gif來初步了解一下這個控件。

下面是一些UIStackView的核心參數(shù)骗卜。

axis

  • horizontal:水平方向布局宠页;
  • vertical:垂直方向布局;

distribution

  • fill:填充整個UIStackView寇仓,并且根據(jù)內(nèi)部子視圖尺寸進(jìn)行動態(tài)調(diào)整举户,可能會拉伸或壓縮某個子視圖,可以通過ContentHuggingPriorityContentCompressionResistancePriority控制拉伸和壓縮的視圖遍烦,后面會講到俭嘁。
  • fillEqually:子視圖等寬或等高,填充整個stackView服猪,過程中會根據(jù)分配的大小改變子視圖尺寸供填。
  • fillProportionally:根據(jù)子視圖intrinsicContentSize按比例布局拐云。
  • equalSpacing:等間距布局,如果stackView放不下則會對子視圖進(jìn)行壓縮近她,默認(rèn)壓縮最后加入的子視圖慨丐。
  • equalCentering:平均分配子視圖得到每個視圖的中心點(diǎn),使用這個中心點(diǎn)來布局每個子視圖泄私,并且保持spacing距離,超出stackView將會壓縮子視圖备闲。

alignment

  • fill:交叉軸方向子視圖鋪滿晌端;
  • top:子視圖頂對其(適用于horizontal布局)
  • center:子視圖居中對齊;
  • bottom:子視圖底對齊(適用于horizontal布局)
  • firstBaseline:按照第一個子視圖的文字的第一行對齊恬砂,并且盡量保證子視圖底對齊(適用于horizontal布局)
  • lastBaseline:按照最后一個子視圖的最后一行對齊咧纠,并且盡量保證子視圖底對齊(適用于horizontal布局)
  • trailing:子視圖右對齊(適用于vertical布局)
  • leading:子視圖左對齊(適用于vertical布局)

spacing

子控件之間的最小距離,根據(jù)下面的圖片結(jié)合上面的枚舉值聯(lián)系起來比較好理解泻骤。

基礎(chǔ)方法

UIStackView的使用很多人都知道漆羔,這里舉一個簡單的例子,兩個UILabel中間有一個分割線狱掂,并且整體居中對齊演痒。

對于傳統(tǒng)的Masonry布局,需要寫不少布局代碼趋惨,而且為了整體居中鸟顺,需要在外面包一層UIView進(jìn)行居中的布局。而使用UIStackView器虾,布局代碼就下面這些讯嫂,單獨(dú)給中間的分割線指定個size,就是唯一涉及Masonry的處理兆沙。

[self.stackView addArrangedSubview:self.privacyButton];
[self.stackView addArrangedSubview:self.declareLineView];
[self.stackView addArrangedSubview:self.createContentDeclare];

[self.declareLineView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(Pixel_1, 11.f));
}];

- (UIStackView *)stackView {
    if (!_stackView) {
        _stackView = [[UIStackView alloc] init];
        _stackView.axis = UILayoutConstraintAxisHorizontal;
        _stackView.alignment = UIStackViewAlignmentFill;
        _stackView.spacing = 8;
    }
    return _stackView;
}

需要注意的是欧芽,UIStackView添加子視圖,需要通過下面指定方法進(jìn)行葛圃,否則子視圖布局會有問題千扔。調(diào)用此方法后就不用再調(diào)用addSubview方法,移除時直接調(diào)用removeFromSuperview即可装悲。

- (void)addArrangedSubview:(UIView *)view;

使用進(jìn)階

隱藏子視圖

上面的布局場景很簡單昏鹃,但如果是下面這種復(fù)雜搜索欄的場景,就很適合用UIStackView诀诊,通常搜索欄中的按鈕會要求某些條件下展示洞渤,某些條件下隱藏,同樣的搜索欄的寬度也是動態(tài)變化的属瓣。例如未登錄時沒有搜索欄右側(cè)的10086客服電話按鈕载迄,搜索欄右側(cè)貼著消息按鈕的讯柔。

對于這種場景,只需要將10086按鈕的hidden設(shè)置為true护昧,則可以實(shí)現(xiàn)上述效果魂迄。UIStackView在檢測到某個子視圖被hidde后,則這個子視圖不參與占位惋耙。

可以通過下面的動畫直觀的感受下hidden的方便捣炬。

抗拉伸、抗壓縮

UIStackView并不能完全替代Masonry绽榛,除了其自帶的布局功能外湿酸,還需要處理子視圖的size、抗拉伸灭美、抗擠壓推溃,以及stackView其自身的布局處理。下面是兩個抗拉伸和抗壓縮的API届腐。

設(shè)置抗拉伸級別铁坎。默認(rèn)值250,控件級別設(shè)置越高犁苏,越不容易被拉伸硬萍。如果不設(shè)置優(yōu)先級,則排在最前的子視圖會被拉伸围详。

- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis;

設(shè)置抗壓縮級別襟铭。默認(rèn)值750,控件級別設(shè)置越高短曾,越不容易被壓縮寒砖。如果不設(shè)置優(yōu)先級,則排在最后的子視圖會被壓縮嫉拐。如果修改最后的子視圖優(yōu)先級為defaultHigh哩都,系統(tǒng)會找750優(yōu)先級中最后的子視圖進(jìn)行壓縮。

- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis;

這里通過一個例子講一下抗拉伸的業(yè)務(wù)場景婉徘,抗壓縮也是同樣的道理漠嵌。假設(shè)有一個場景,一個horizontalstackView有兩個UILabel盖呼,這兩個label的文案都是動態(tài)下發(fā)的儒鹿,產(chǎn)品需求是左側(cè)自適應(yīng)展示標(biāo)簽文案,右側(cè)文案展示不下打點(diǎn)几晤。

這種場景如果用布局來做會很復(fù)雜约炎,增加很多計算操作。用UIStackView實(shí)現(xiàn)就很簡單,我們需要保證的是不拉伸左側(cè)label圾浅,只需要給左邊label設(shè)置抗拉伸優(yōu)先級高一些即可實(shí)現(xiàn)掠手。

tagLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)

不足點(diǎn)

相對于前端的Flex布局,UIStackView對某個子視圖可做的處理很有限狸捕。Flex除了可以對容器自身進(jìn)行布局設(shè)置喷鸽,即開頭介紹的部分,也可以對Flex布局中的子視圖進(jìn)行單獨(dú)布局設(shè)置灸拍。下面是一些Flex對子視圖的一些實(shí)用屬性做祝,可以了解下。

  • orderFlex的每個子視圖order默認(rèn)都是0鸡岗,如果想讓某個視圖排列在最前面剖淀,可以將order設(shè)置為-1,同樣的纤房,如果想讓子視圖展示在最后,可以將order設(shè)置為1翻诉;
  • flex-grow:可以設(shè)置某個子視圖的擴(kuò)展炮姨,擴(kuò)展指的是這個子視圖是否占據(jù)除元素外的空白區(qū)域,取值范圍是01碰煌,例如設(shè)置為1則表示占據(jù)全部空白區(qū)域舒岸;
  • flex-basis:通過這個屬性可以設(shè)置某個子視圖占據(jù)多少寬度,默認(rèn)是auto由瀏覽器分配寬度芦圾,如果設(shè)置的寬度超過父視圖蛾派,則子視圖會進(jìn)行等比收縮;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末个少,一起剝皮案震驚了整個濱河市洪乍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夜焦,老刑警劉巖壳澳,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異茫经,居然都是意外死亡巷波,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門卸伞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抹镊,“玉大人,你說我怎么就攤上這事荤傲】宥” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵遂黍,是天一觀的道長氨菇。 經(jīng)常有香客問我儡炼,道長,這世上最難降的妖魔是什么查蓉? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任乌询,我火速辦了婚禮,結(jié)果婚禮上豌研,老公的妹妹穿的比我還像新娘妹田。我一直安慰自己,他們只是感情好鹃共,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布鬼佣。 她就那樣靜靜地躺著,像睡著了一般霜浴。 火紅的嫁衣襯著肌膚如雪晶衷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天阴孟,我揣著相機(jī)與錄音晌纫,去河邊找鬼。 笑死永丝,一個胖子當(dāng)著我的面吹牛锹漱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慕嚷,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哥牍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了喝检?” 一聲冷哼從身側(cè)響起嗅辣,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挠说,沒想到半個月后辩诞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纺涤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年译暂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撩炊。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡外永,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拧咳,到底是詐尸還是另有隱情伯顶,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站祭衩,受9級特大地震影響灶体,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掐暮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一蝎抽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧路克,春花似錦樟结、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至灰羽,卻和暖如春驮履,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背廉嚼。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工玫镐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人前鹅。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像峭梳,于是被迫代替她去往敵國和親舰绘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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