使用UIStackView來簡化iOS的介面佈局
theme: smartblue highlight: xcode
我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第1篇文章,點選檢視活動詳情”
前言
在過去iOS
頁面佈局較為傳統,大多數人使用Frame
或者AutoLayout
來佈局,在iOS9
以後,引入了UIStackView
。UIStackView
是用於線性佈局的控制元件,可以自動管理子檢視佈局,自動填充。它借鑑了前端的佈局演算法Flexbox
,可以簡便地實現各種頁面佈局。
UIStackView
雖然已經不是新控制元件了,但還是有很多同學並沒有使用起來。通常有時改別人的程式碼看到亂糟糟的佈局程式碼就有很多槽點。所以這也是寫這篇文章的目的所在,真的推薦大家使用StackView。事半功倍,省下來的時間摸魚不香嘛。
迴歸正題,不管是使用Frame
或者AutoLayout
來佈局,我們都需要對所有的控制元件的位置、大小進行設定,Frame
需要指定位置佈局,AutoLayout
需要指定約束佈局;而UIStackView
佈局方式凸顯它的優勢在於不需要設定排列檢視(即子檢視)的位置,大小(不是必須的),而是通過自身的排列、分佈方式自動完成佈局。對比起來,使用UIStackView
更高效,我們可以通過巢狀UIStackView
快速完成各式各樣的佈局。
UIStackView佈局思想
UIStackView
的初衷就是為了簡化的介面佈局,適用於列或行中佈局檢視集合。
StackView
使用自動佈局(AutoLayout
)來定位和設定其排列檢視的大小。StackView
將第一個和最後一個排列的檢視與其沿堆疊軸的邊緣對齊。在水平堆疊中,這意味著第一個排列檢視的前緣被固定在StackView
的前緣上,而最後一個排列檢視的後緣被固定在StackView
的後緣上;在垂直堆疊中,頂部和底部邊緣分別固定在堆疊的頂部和底部邊緣上。
StackView
會根據自身的佈局規則進行填充排列檢視。
distribution:
distribution
即排列方式:
- fill
根據抗拉伸、壓縮優先順序填充(預設拉伸第一個排列檢視)
- fillEqually
在排列方向上的填充大小相同(即橫向佈局寬度相同,縱向佈局高度相同)
- fillProportionally
根據排列檢視的大小按比例填充
- equalSpacing
均勻地填充檢視之間的間距
- equalCentering
根據排列檢視中心點之間的相同間隔填充
alignment:
alignment
即對齊方式:(垂直於排列方向)
- fill
填充排列檢視到StackView
的可用空間
- top
以StackView
的頂部排列(與之相似的是leading
)
- bottom
以StackView
的尾部排列(與之相似的是trailing
)
- center
以StackView
的中間排列
- firstBaseline
以第一個基準線排列
- lastBaseline
以最後一個的基準線排列
如需設定排列檢視之間的間距可以通過設定space
屬性,若是排列檢視之間的間距不同,可以使用方法指定某個排列檢視的間距(此方法iOS11以上使用),或者使用一個無用的view插入在檢視之間替代間隙,此view僅作為間距使用(使用xib
、Storyboard
會經常使用此類方法,可以參照)。
當你真的瞭解UIStackView的這些佈局思想之後,你就會知道它能幫你解決很多繁瑣的佈局。(如一個多變的底部操作欄、一行大小各異的控制元件等等)
從上面的佈局思想中,不難看出,其實我們僅需要確定StackView
的排列方向,以及排列方式、對其方式,就能大體上對整個排列檢視初步的佈局,而後在根據不同的檢視進行大小上的調整以及間距的調整即可。
使用UIStackView
來自動佈局子檢視,你只需要每個子檢視關注自身的大小即可。
以此類操作欄為例,舉個栗子🌰:
先說說我們常用的佈局方式,可能還是會有一部分人會選擇Frame
佈局,或者AutoLayout
佈局。
但此類UI在設計之初,通常會有很多狀態、特徵,每一種狀態下,控制元件都會變化。
那麼Frame
佈局在這種佈局容易變化的情況下,就顯得有非常的繁瑣,佈局程式碼非常的多,並且狀態很多的時候不好維護。
同樣AutoLayout
也是如此,需要寫很多的更新佈局約束。
這個時候,借用UIStackView
的思想,我們可以很簡單的實現這個佈局。每個控制元件只關注自身大小,不會對其他的空間產生依賴關係,在需要時顯示出來,不需要時隱藏起來。
我們先以文字輸入入口“說點什麼”小試牛刀。
下面就是用StackView佈局的效果。
這裡我是使用的xib結合StackView。如果我們平時使用的程式碼佈局,也可以使用程式碼結合StackView佈局,這樣也會減少很多程式碼量,可以自行腦補。
UIStackView用法
初始化
與其他控制元件一樣的初始化方式;
- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
當然也可以選擇專屬的初始化方式;
- (instancetype)initWithArrangedSubviews:(NSArray<__kindof UIView *> *)views;
新增、刪除子檢視
- (void)addArrangedSubview:(UIView *)view;
- (void)removeArrangedSubview:(UIView *)view;
排列方向
``` @property(nonatomic) UILayoutConstraintAxis axis;
typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) { UILayoutConstraintAxisHorizontal = 0, // 水平方向 UILayoutConstraintAxisVertical = 1 // 垂直方向 }; ```
佈局方式
``` @property(nonatomic) UIStackViewDistribution distribution;
typedef NS_ENUM(NSInteger, UIStackViewDistribution) { UIStackViewDistributionFill = 0, //子檢視填充滿指定方向,優先拉伸第一個控制元件 UIStackViewDistributionFillEqually, //每個子檢視填充大小相等, UIStackViewDistributionFillProportionally, //根據每個子視圖裡面內容的尺寸來進行填充操作 UIStackViewDistributionEqualSpacing, //每個子檢視之間的間距相等 UIStackViewDistributionEqualCentering, //每個子檢視中心直接的間距相等 } API_AVAILABLE(ios(9.0)); ```
對齊方式
``` @property(nonatomic) UIStackViewAlignment alignment;
typedef NS_ENUM(NSInteger, UIStackViewAlignment) { UIStackViewAlignmentFill, //水平:subView的上下和StackView的上下邊距 相等 垂直: subView的左右邊距和 StackView的所有相等 UIStackViewAlignmentLeading,//垂直有效 :左對齊 UIStackViewAlignmentTop = UIStackViewAlignmentLeading, // 水平有效 上對齊 UIStackViewAlignmentFirstBaseline,//水平有效,第一行基準線對齊。 UIStackViewAlignmentCenter, //中心基準線對齊 1.水平 高度中點對齊 2.垂直:寬度中點對齊 UIStackViewAlignmentTrailing, //垂直有效,右邊界對齊。 UIStackViewAlignmentBottom = UIStackViewAlignmentTrailing,// 水平有效 ,下邊界對齊。 UIStackViewAlignmentLastBaseline,//水平有效,最後一行基準線對齊。 } API_AVAILABLE(9_0); ```
間距
@property(nonatomic) NSInteger space; //排列檢視相鄰邊緣之間的距離。
- LeetCode 初級演算法之陣列(上),看看你都學會了嗎?
- LeetCode 初級演算法之連結串列,看看你都學會了嗎?
- LeetCode 初級演算法之字串(上),看看你都學會了嗎?
- 純程式碼佈局,也可以一樣的簡潔
- UIStackView之一問一答
- 使用UIStackView來簡化iOS的介面佈局
- 夏天來了,iOS開發者們該如何減少App耗電?(上)
- 夏天來了,App開發者們如何看待手機發燙問題?
- 聊聊iOS中UITableView複用的那些事
- 曾經經典的微信打飛機遊戲還有人記得嗎?
- iOS 原生渲染與 Flutter 有什麼區別 (上)
- 瞭解 Mach-O檔案
- CocoaPods中podsepc檔案設定詳解
- iOS 原生渲染與 Flutter 有什麼區別 (下)
- 簡單瞭解 iOS CVPixelBuffer (上)
- 談談 iOS 包瘦身方案
- 播放器重構的探索之路
- 如何使用CocoaPods製作私有庫
- iOS 元件化方案