Painted painted levels: fostered fostered fostered
Tags: “iOS Layout” “iOS Frame” “iOS Frame Bounds” by Xs·H
When I shared the automatic layout of iOS UIButton according to the content in Mulinlo offline, I discussed the common layout mode of iOS with my front-end classmates. The discussion process is very lively and not easy to record, but the author thinks it is necessary to record the results of the discussion, hoping to help some students.
The author classifies the most popular iOS layouts into Frame, Autoresizing, Constraint, StackView, and navigation, and explains them one by one. This article introduces Frame.
Frame is a UIView property that describes the origin and size of the view represented by UIView and its subclasses. Frame is the most basic, most commonly used, and most acceptable layout in iOS. In general, you can easily create and display a view by doing the following.
- (void)viewDidLoad {
[super viewDidLoad];
_contentView = [[QiFrameContentView alloc] initWithFrame:self.view.bounds];
_contentView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:_contentView];
}
Copy the code
In the above code, the author adds a light gray contentView to self.view in viewDidLoad and sets its frame to self.view.bounds. Obviously, the author wants the light gray contentView to completely cover self.view (white by default). Use the simulator to run it. The initial effect is exactly what the author expects, but after rotating the simulator, the light gray contentView does not rotate together, and a part of the white self.view is left on the right side, as shown below.
The above phenomenon is actually a manifestation of the frame property. When a view is laid out using only frames, the position and size of the view are uniquely determined and do not change with the parent view unless the frame is set again at some point.
The author wanted the contentView to be rotated along with self.view, so it would always be completely covered, so he made the following changes.
- (void)viewDidLoad {
[super viewDidLoad];
_contentView = [[QiFrameContentView alloc] initWithFrame:CGRectZero];
_contentView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:_contentView];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
_contentView.frame = self.view.bounds;
}
Copy the code
To achieve the desired size, the author resets the frame of the contentView in the viewWillLayoutSubviews method and changes the frame set when initializing the contentView in viewDidLoad to CGRectZero. The viewWillLayoutSubviews method is triggered every time the frame of self.view changes and every time the child of self.view changes.
Referring to the above principle, the author adds 4 subviews to contentView to achieve the effect of 4 equal parts, as shown in the figure below.
The code to achieve the above effect is as follows:
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_subView1 = [[UIView alloc] initWithFrame:CGRectZero];
_subView1.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:.6];
[self addSubview:_subView1];
_subView2 = [[UIView alloc] initWithFrame:CGRectZero];
_subView2.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:.6];
[self addSubview:_subView2];
_subView3 = [[UIView alloc] initWithFrame:CGRectZero];
_subView3.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:.6];
[self addSubview:_subView3];
_subView4 = [[UIView alloc] initWithFrame:CGRectZero];
_subView4.backgroundColor = [[UIColor yellowColor] colorWithAlphaComponent:.6];
[self addSubview:_subView4];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
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.frame = CGRectMake(margin, margin, width, height);
_subView2.frame = CGRectMake(margin + width + padding, margin, width, height);
_subView3.frame = CGRectMake(margin, margin + height + padding, width, height);
_subView4.frame = CGRectMake(margin + width + padding, margin + height + padding, width, height);
/*
_subView4.qi_width = width;
_subView4.qi_height = height;
_subView4.qi_top = _subView3.qi_top;
_subView4.qi_left = _subView3.qi_right + padding;
*/
}
Copy the code
The layoutSubviews method in contentView and viewWillLayoutSubviews method in viewController are triggered in pairs, and layoutSubviews are later than the latter.
PS: There is a difference between bounds and frame. Bounds only describes the size of a view, like a page of A4, and its bounds remain unchanged whether it is placed on the table or the floor. A frame can describe a view’s position in addition to its size. Another example is A4 paper, moved from the table to the floor, its frame has changed.
Also, to make it easier and more intuitive to use the Frame layout view, you can use a code form similar to the comments in the code above. The implementation details can be viewed in QiLayoutDemo.
Recommended articles:
IOS UIButton automatically layouts based on content iOS specified initialization method hitTest method in UIView