iOS——frame和bounds的区别

把frame理解为占用区域,把bounds理解为边界。View在旋转过程中,其实自己的坐标系统并没有发生改变,bounds中的origin只能通过setBounds方法修改。

frame 定义了视图在其父视图坐标系统中的位置和大小。其坐标系是相对于俯视图的坐标系。

bounds 定义了视图自身坐标系统中的位置和大小。其坐标系是相对于自己本身视图的坐标系。

UIView.h中的注释:

objc 复制代码
// 如果视图进行了变换,不要使用 frame,因为它不会正确反映视图的实际位置。使用 bounds + center 代替。
@property(nonatomic) CGRect frame;

// 如果非恒等变换,请使用 bounds/center 而不是 frame。
@property(nonatomic) CGRect bounds;      // 默认 bounds 是原点为零,大小为 frame 的大小。
@property(nonatomic) CGPoint center;      // center 是 frame 的中心,相对于 anchorPoint。
  • bounds的x,y是根据自己的坐标系统而言的。没错,每个view都有自己的坐标系。以自己左上角点为坐标原点。所以bounds的x,y默认为(0,0),除非调用setBounds方法;
  • frame的size不一定等于bounds的size,在旋转后它们的size就不一样了。

有如下示例:

objc 复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *animateButton = [UIButton buttonWithType:UIButtonTypeSystem];
    animateButton.frame = CGRectMake(100, 250, 100, 50);
    [animateButton setTitle:@"Animate" forState:UIControlStateNormal];
    [animateButton addTarget:self action:@selector(startAnimation) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:animateButton];
    
    self.fView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    [self.view addSubview:self.fView];
    self.fView.backgroundColor = [UIColor orangeColor];
    
    self.sView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
    [self.fView addSubview:self.sView];
    self.sView.backgroundColor = [UIColor blueColor];
    
    NSLog(@"Bounds:");
    NSLog(@"fView x:%f; sView x:%f", self.fView.bounds.origin.x, self.sView.bounds.origin.x);
    NSLog(@"fView y:%f; sView y:%f", self.fView.bounds.origin.y, self.sView.bounds.origin.y);
    
    NSLog(@"frame:");
    NSLog(@"fView x:%f; sView x:%f", self.fView.frame.origin.x, self.sView.frame.origin.x);
    NSLog(@"fView y:%f; sView y:%f", self.fView.frame.origin.y, self.sView.frame.origin.y);
}

- (void) startAnimation {
    [self.fView setBounds:CGRectMake(60, 60, 100, 100)];
    
    NSLog(@"Bounds:");
    NSLog(@"fView x:%f; sView x:%f", self.fView.bounds.origin.x, self.sView.bounds.origin.x);
    NSLog(@"fView y:%f; sView y:%f", self.fView.bounds.origin.y, self.sView.bounds.origin.y);
    
    NSLog(@"frame:");
    NSLog(@"fView x:%f; sView x:%f", self.fView.frame.origin.x, self.sView.frame.origin.x);
    NSLog(@"fView y:%f; sView y:%f", self.fView.frame.origin.y, self.sView.frame.origin.y);
}

点击按钮我们发现,明明更改的是fView的bounds,为什么fView的位置没变,但是sView的位置向左上了呢?

其实setBounds中的(x,y)只改变自己的坐标系统,子View的bounds和frame并不会改变;

setBounds是修改自己坐标系的原点位置,进而影响到子View的显示位置;

bounds改变位置时,改变的是子视图的位置,自身没有影响,其实就是改变了自身的坐标系原点,默认原点在左上角。

因此执行完setBounds后,实际上是将当前fView的视图的原点移到了相对于原来原点的(60,60)位置,但是由于fView设定的frame是(100,100),因此它本身的frame不变,只是相当于移动了坐标系往左上了。又因为sView是fView的子视图,sView的frame是相对于fView的坐标系来设定位置的,因此,sView还是处于相对于fView的(0,0)位置,因此我们看上去sView的位置就像是随着fView的坐标系一起向左上移动了,但实际上sView的frame没有改变,打印出来还是(0,0)。

总结

frame: 描述视图在其父视图中的位置和大小,是"绝对"的。

bounds: 描述视图自身的内容区域和尺寸,是"相对"的。

相关推荐
玫瑰花开一片一片11 小时前
Flutter IOS 真机 Widget 错误。Widget 安装后系统中没有
flutter·ios·widget·ios widget
烎就是我13 小时前
100行代码swift从零实现一个iOS日历
ios·swift
鸿蒙布道师1 天前
鸿蒙NEXT开发通知工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师1 天前
鸿蒙NEXT开发网络相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
cauyyl1 天前
xcode 16 遇到contains bitcode
react native·xcode
余生大大1 天前
关于Safari浏览器在ios<16.3版本不支持正则表达式零宽断言的解决办法
ios·正则表达式·safari
A_ugust__1 天前
Vue3集成浏览器API实时语音识别
人工智能·语音识别·xcode
爱分享的程序员1 天前
前端跨端框架的开发以及IOS和安卓的开发流程和打包上架的详细流程
android·前端·ios
Macle_Chen1 天前
ios开发中xxx.debug.dylib not found
ios·bug·debug.dylib