布局子视图
- 布局子视图
- 手动布局子视图
- 自动布局子视图
- 总结
布局子视图
当我们想让子视图随着父视图的变化跟着变化时,我们需要选择使用手动布局子视图或者自动布局子视图两个方法之一。
手动布局子视图
先来学习手动布局子视图。
首先,我们先创建一个父视图superView,
然后在ViewController中,实现两个内容:
- 创建一个父视图
- 创建两个按钮,控制视图放大缩小。
我们使用UIView的 animateWithDuration: animations:方法来制作控制视图放大缩小的效果,该方法传入两个参数
-
duration(持续时间):这是动画的持续时间,以秒为单位。它指定了从动画开始到动画结束所经过的时间。在指定的持续时间内,UIKit 框架会根据动画块中的属性更改逐渐过渡到新的属性值。
-
animations(动画块):使用代码块更视图属性。在这个代码块中,可以修改视图的位置、大小、透明度等属性,UIKit 框架会在指定的持续时间内,根据动画块中的属性更改逐渐过渡到新的属性值。
#import "ViewController.h"
#import "SuperView.h"
@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.//创建父视图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
然后在父视图中接口文件中定义四个子视图属性,和创建子视图的方法。
//superView.h文件
#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 beginAnimations:nil context:nil];
// [UIView setAnimationDuration:1];
// _view01.frame = CGRectMake(0, 0, 40, 40);
// _view02.frame = CGRectMake(self.bounds.size.width - 40, 0, 40, 40);
// _view03.frame = CGRectMake(self.bounds.size.width - 40, self.bounds.size.height-40, 40, 40);
// _view04.frame = CGRectMake(0, self.bounds.size.height - 40, 40, 40);
// //新版[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];// Do any additional setup after loading the view.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;//语句会覆盖//viewCenter.autoresizingMask = 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:)设置视图之间的约束关系,从而实现自动布局。