布局子视图
当我们想让子视图随着父视图的变化跟着变化时,我们需要选择使用手动布局子视图或者自动布局子视图两个方法之一。
手动布局子视图
先来学习手动布局子视图。
首先,我们先创建一个父视图superView,
我们使用UIView的 animateWithDuration: animations:方法来制作控制视图放大缩小的效果,该方法传入两个参数
-
duration(持续时间):这是动画的持续时间,以秒为单位。它指定了从动画开始到动画结束所经过的时间。在指定的持续时间内,UIKit 框架会根据动画块中的属性更改逐渐过渡到新的属性值。
-
animations(动画块):使用代码块更视图属性。在这个代码块中,可以修改视图的位置、大小、透明度等属性,UIKit 框架会在指定的持续时间内,根据动画块中的属性更改逐渐过渡到新的属性值。
#import "ViewController.h"
#import "SuperView.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
SuperView *sView = [[SuperView alloc] init];
sView.frame = CGRectMake(20, 50, 180, 280);
sView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:sView];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(240, 580, 80, 40);
[btn setTitle:@"放大" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(pressLarge) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
UIButton *btn02 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn02.frame = CGRectMake(240, 620, 80, 40);
[btn02 setTitle:@"缩小" forState:UIControlStateNormal];
[btn02 addTarget:self action:@selector(pressSmall) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn02];
sView.tag = 101;
[sView creatSubViews];
}
- (void) pressLarge {
SuperView *sView = (SuperView*)[self.view viewWithTag: 101];
[UIView animateWithDuration:1.0 animations:^{
sView.frame = CGRectMake(20, 50, 300, 480);
}];
}
- (void) pressSmall {
SuperView *sView = (SuperView*)[self.view viewWithTag: 101];
[UIView animateWithDuration: 1.0 animations: ^{
sView.frame = CGRectMake(20, 50, 180, 280);
}];
}
@end
然后在父视图中接口文件中定义四个子视图属性,和创建子视图的方法。
#import <UIKit/UIKit.h>
@interface SuperView : UIView
{
UIView *_view01;
UIView *_view02;
UIView *_view03;
UIView *_view04;
}
-(void) creatSubViews;
@end
然后我们在实现文件中创建这四个子视图,并且手动布局子视图随着父视图的变化而改变。
注意的是,从iOS13.0起,弃用了beginAnimations: context:的方法,而改用基于代码块的动画实现这一功能。但是两者依旧都能运行,此处给出了两种方法的代码。我们还运用了-(void) layoutSubviews方法:
- layoutSubviews : UIView 类中的一个方法,它在视图需要重新布局其子视图时被调用。在视图层次结构发生变化或视图的大小发生改变时,系统会自动调用 layoutSubviews 方法,以便进行子视图的重新布局。
#import "SuperView.h"
@implementation SuperView
-(void) creatSubViews
{
_view01 = [[UIView alloc] init];
_view01.frame = CGRectMake(0, 0, 40, 40);
_view02 = [[UIView alloc] init];
_view02.frame = CGRectMake(self.bounds.size.width - 40, 0, 40, 40);
_view03 = [[UIView alloc] init];
_view03.frame = CGRectMake(self.bounds.size.width - 40, self.bounds.size.height-40, 40, 40);
_view04 = [[UIView alloc] init];
_view04.frame = CGRectMake(0, self.bounds.size.height - 40, 40, 40);
_view01.backgroundColor = [UIColor blueColor];
_view02.backgroundColor = [UIColor blueColor];
_view03.backgroundColor = [UIColor blueColor];
_view04.backgroundColor = [UIColor blueColor];
[self addSubview:_view01];
[self addSubview:_view02];
[self addSubview:_view03];
[self addSubview:_view04];
}
-(void) layoutSubviews
{
[UIView animateWithDuration: 1.0 animations:^ {
self->_view01.frame = CGRectMake(0, 0, 40, 40);
self->_view02.frame = CGRectMake(self.bounds.size.width - 40, 0, 40, 40);
self->_view03.frame = CGRectMake(self.bounds.size.width - 40, self.bounds.size.height - 40, 40, 40);
self->_view04.frame = CGRectMake(0, self.bounds.size.height - 40, 40, 40);
}];
}
@end
效果(放大前):
自动布局子视图
手动布局子视图需要我们自己手动调整子视图的原点位置,我们还可以自动控制子视图对齐。
需要注意:我们在viewController视图控制器中创建四个UILabel控件子视图,便于区别。
首先,我们在接口部分定义属性
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
UIView *superView;
UILabel *label1;
UILabel *label2;
UILabel *label3;
UILabel *label4;
UIView *viewCenter;
}
@end
在实现部分中,我们首先创建接口部分中的六个视图。
再通过- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event方法,使用一个局部布尔变量储存当前屏幕状态,实现点击改变父视图大小。
再通过修改View的autoresizingMask自动调整布局属性,实现自动布局子视图。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
superView = [[UIView alloc] init];
superView.frame = CGRectMake(20, 20, 180, 280);
superView.backgroundColor = [UIColor blueColor];
label1 = [[UILabel alloc] init];
label1.text = @"1";
label1.frame = CGRectMake(0, 0, 40, 40); label1.backgroundColor = [UIColor greenColor];
label2 = [[UILabel alloc] init];
label2.frame = CGRectMake(180 - 40, 0, 40, 40);
label2.text = @"2";
label2.backgroundColor = [UIColor greenColor];
label3 = [[UILabel alloc] init];
label3.frame = CGRectMake(180-40, 280-40, 40, 40);
label3.text = @"3";
label3.backgroundColor = [UIColor greenColor];
label4 = [[UILabel alloc] init];
label4.frame = CGRectMake(0, 280-40, 40, 40);
label4.text = @"4";
label4.backgroundColor = [UIColor greenColor];
[superView addSubview:label1];
[superView addSubview:label2];
[superView addSubview:label3];
[superView addSubview:label4];
[self.view addSubview:superView];
viewCenter = [[UIView alloc] init];
viewCenter.frame = CGRectMake(0, 0, superView.bounds.size.width, 40);
viewCenter.center = CGPointMake(180/2, 280/2);
viewCenter.backgroundColor = [UIColor orangeColor];
[superView addSubview:viewCenter];
label2.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
label4.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
label3.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
viewCenter.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
}
- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
static BOOL isLarge = NO;
[UIView animateWithDuration: 1.0 animations:^{
if (isLarge == NO) {
self->superView.frame = CGRectMake(10, 10, 350, 580);
} else {
self->superView.frame = CGRectMake(20, 20, 180, 280);
}
isLarge = !isLarge;
}];
}
@end
效果(放大前):
总结
我们以一个问题来总结:为什么手动布局子视图在父视图的文件中创建子视图,而自动布局子视图在视图控制器中创建子视图呢?
这两种不同的布局方式,在视图的管理和实现上也有不同。因此他们的位置是不同的。
- 手动布局:通过直接设置视图的 frame 属性或使用类似的布局方法来手动计算和设置子视图的位置和大小。在这种情况下,布局的逻辑通常集中在父视图中,因为父视图更了解自己的布局需求和子视图的相对关系。因此,在手动布局中,在父视图中的 layoutSubviews 方法中进行子视图的布局计算和设置。
- 自动布局:使用 Auto Layout 技术进行视图布局的一种方式,它通过使用约束来描述和管理视图之间的关系。在自动布局中,视图的布局逻辑通常由视图的父视图的视图控制器来管理。视图控制器负责设置视图之间的约束关系,以及处理视图的自动布局。因此,在自动布局中,视图控制器通常会在适当的方法中(如 viewDidLoad 或 viewWillAppear:)设置视图之间的约束关系,从而实现自动布局。