級別: ★☆☆☆☆
標簽:「iOS布局」「iOS autoresizing」「autoresizingMask」
作者: Xs·H
審校: QiShare團隊
在 沐靈洛 線下分享iOS UIButton根據內容自動布局時,有和前端同學討論到iOS的常用布局方式。討論過程十分熱鬧,不容易記錄,但作者認為討論結果有必要記錄一下,希望能幫助到一些同學。
作者將iOS常用布局方式歸納為Frame、Autoresizing、Constraint、StackView和Masonry五種,并將逐一介紹。
本篇文章介紹Autoresizing。
autoresizing是iOS較早版本中出現的屏幕適配技術。當時,iOS設備機型少、app界面布局簡單,autoresizing可以較好地完成比如橫豎屏之類的視圖適配需求。在QiShare的項目中,autoresizing常與frame結合著使用來達到某些適配效果。比如,與上篇文章對比,用autoresizing可以更快速地實現淺灰色contentView完全覆蓋self.view并與之一起旋轉的效果,代碼如下。
- (void)viewDidLoad {
[super viewDidLoad];
_contentView = [[QiAutoresizingContentView alloc] initWithFrame:self.view.bounds];
_contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_contentView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:_contentView];
}
在上述代碼中,contentView的autoresizingMask屬性起到了決定性作用。我們來認識下這個屬性。
@property(nonatomic) UIViewAutoresizing autoresizingMask; // simple resize. default is UIViewAutoresizingNone
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
contentView的autoresizingMask屬性是一個位移枚舉UIViewAutoresizing。UIViewAutoresizing將視圖分為了LeftMargin(相對于父視圖的左邊距)、RightMargin(相對于父視圖的右邊距)、TopMargin(相對于父視圖的上邊距)、BottomMargin(相對于父視圖的下邊距)、Width(視圖自身的寬)和Height(視圖自身的高)6個屬性。在不設置autoresizingMask時默認使用UIViewAutoresizingNone賦值。當將autoresizingMask設置為某一個或多個值后,即設定該view的對應屬性可以隨著父視圖的變化而變化。
比如在上述代碼中,contentView的autoresizingMask被賦值為UIViewAutoresizingFlexibleWidth和UIViewAutoresizingFlexibleHeight,即設定contentView除了Width和Height可以隨著self.view的變化而變化外,其余4個屬性都被固定住了,所以能達到預期的效果,如下。
接下來,作者嘗試使用autoresizing實現上篇文章中4等分的效果,代碼如下。
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
CGFloat margin = 20.0;
CGFloat padding = 20.0;
CGFloat width = (self.bounds.size.width - margin * 2 - padding) / 2;
CGFloat height = (self.bounds.size.height - margin * 2 - padding) / 2;
_subView1 = [[UIView alloc] initWithFrame:CGRectMake(margin, margin, width, height)];
_subView1.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:.6];
[self addSubview:_subView1];
_subView2 = [[UIView alloc] initWithFrame:CGRectMake(margin + width + padding, margin, width, height)];
_subView2.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:.6];
[self addSubview:_subView2];
_subView3 = [[UIView alloc] initWithFrame:CGRectMake(margin, margin + height + padding, width, height)];
_subView3.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:.6];
[self addSubview:_subView3];
_subView4 = [[UIView alloc] initWithFrame:CGRectMake(margin + width + padding, margin + height + padding, width, height)];
_subView4.backgroundColor = [[UIColor yellowColor] colorWithAlphaComponent:.6];
[self addSubview:_subView4];
_subView1.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
_subView2.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin;
_subView3.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
_subView4.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
}
return self;
}
實現的效果圖如下。
觀察上圖,在旋轉屏幕至橫屏后,4個subView之間的間距出了問題。這是因為UIViewAutoresizing枚舉中的6個值都是相對于父視圖的,不能實現同級視圖之間存在約束關系的場景需求。
要實現同級視圖之間的約束需求,閱讀下篇文章要講的Constraint會大有幫助。
另外,作者對contentView做了一個縮放動畫,可以更好地觀察視圖的變化情況。具體細節可以在QiLayoutDemo中查看。