使用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 組件化方案