LayoutMargin & preservesSuperviewLayoutMargins 学习笔记

发现问题

在IB中拖放tableView,大小为设置为屏幕大小后,添加了四个方向的约束,发现,约束的值居然不是和想象中不太一样,不是0。

1.png

接着打开attribute inspector,发现约束信息如下:


2.png

在这里发现Second Item是superView 的 leading Margin. 而不是superView的leading,所以约束的值不是0,但leading margin又是什么?

Layout Magrin

通过查找文档,发现这是iOS 8 以后,UIView 新增的一个属性,layoutMargins. 表示一个View的内边距。

文档

@property(nonatomic) UIEdgeInsets layoutMargins;
The default spacing to use when laying out content in the view.

typedef struct UIEdgeInsets {
    CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
} UIEdgeInsets;

这个属性类似Android中的padding,用于父View设置子View布局的内边距。

The default margins are eight points on each side.

默认值是8个点,可修改。

If the view is a view controller’s root view, the system sets and manages the margins. The top and bottom margins are set to zero points. The side margins vary depending on the current size class, but can be either 16 or 20 points. You cannot change these margins.

但如果,是ViewController的rootView,layoutMargins 是系统设置和控制的,不能修改。(文章最开始的tableView到 leading Margin 约束为 -16.就说明,left margin是16点。)

到这里,其实对layoutMargins理解都较为清晰,但是文档中还提到了一个与layoutMargins 相关的属性: preservesSuperviewLayoutMargins

When the edge of your view is close to the edge of the superview and the preservesSuperviewLayoutMargins property is YES, the actual layout margins may be increased to prevent content from overlapping the superview’s margins.

读完感觉字面意思都懂,但就是不知道是什么意思。

preservesSuperviewLayoutMargins

@property(nonatomic) BOOL preservesSuperviewLayoutMargins;
A Boolean value indicating whether the current view also respects the margins of its superview.
The default value of this property is NO.

一个BOOL值,决定当前View布局是否也考虑父View的layoutMargins.
默认是NO.

到这里还是晕的,没看懂这个属性是干嘛,继续看文档。

文档

When the value of this property is YES, the superview’s margins are also considered when laying out content. This margin affects layouts where the distance between the edge of a view and its superview is smaller than the corresponding margin.

当这个属性是YES的时候,父view的layoutMargins会被考虑到当前View的布局中。也就是说,当前View和父View的内边距,小于父View相应layoutMargins中对应的内边距时,父View的内边距会决定当前View的布局。还是有些抽象。

For example, you might have a content view whose frame precisely matches the bounds of its superview. When any of the superview’s margins is inside the area represented by the content view and its own margins, UIKit adjusts the content view’s layout to respect the superview’s margins. The amount of the adjustment is the smallest amount needed to ensure that content is also inside the superview’s margins.

这里大概的意思就是,你有一个contentView,它的大小和父View一样大的你设置了contentView的preservesSuperviewLayoutMargins为YES,当你对contentView中的子View进行布局的时候,如果有子View的所在位置(比如:子View到contentView的左边距,小于父View的LayoutMargin 对应的左内边距)UIKit就会对子View进行一些调整。
感觉看了这一段稍微清晰了一些,可是写代码想实现一个demo的时候,发现这个preservesSuperviewLayoutMargins属性好像并没有什么卵用。
最后再Google上搜到了这篇文章。
iOS8 Day-by-Day :: Day 32 :: Layout Margins

然后自己实现了一个 demo 如下

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建一个红色的View,大小和手机屏幕一样大,
    //layoutMargin 为(100,100,100,100)
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    redView.layoutMargins = UIEdgeInsetsMake(100, 100, 100, 100);
    [self.view addSubview:redView];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[redView]-(0)-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[redView]-(0)-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    
    //创建一个绿色的View,作为我们的ContentView,父View为红色的View
    //约束为到红色View各边距为10,但红色View 的layoutMargin 还是再绿色View内
    //设置绿色View preservesSuperviewLayoutMargins 为YES
    UIView *greenView = [[UIView alloc] init];
    greenView.backgroundColor = [UIColor greenColor];
    greenView.translatesAutoresizingMaskIntoConstraints = NO;
    greenView.preservesSuperviewLayoutMargins = YES;
    [redView addSubview:greenView];
    [redView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[greenView]-(10)-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(greenView)]];
    [redView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[greenView]-(10)-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(greenView)]];
    
    //创建一个蓝色View,作为绿色View的子View
    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = [UIColor blueColor];
    blueView.translatesAutoresizingMaskIntoConstraints = NO;
    [greenView addSubview:blueView];
    
    //注意,leading 约束对应的第二item 属性为 leading.margin
    [greenView addConstraint: [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:greenView attribute:NSLayoutAttributeLeadingMargin multiplier:1.0 constant:0.0]];
    // trailing 属性 为父View trailig - 8.0// 8.0 是默认layout Margin
    [greenView addConstraint: [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:greenView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:-8.0]];
    [greenView addConstraint: [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:greenView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
    [greenView addConstraint: [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:greenView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
}
3.png

总结

最后总结一下preservesSuperviewLayoutMargins生效的要点:(如果总结的不对希望大家指正~)
1.preservesSuperviewLayoutMargins 只在自动布局情况下生效
2.contentView(设置preservesSuperviewLayoutMargins的View)的父View的LayoutMargin中,至少存在contentView 某一个方向到父View的边距,小于父View LayoutMargin 对应的内边距。(就比如上面栗子中,绿色View到红色View的左边距是10,红色View的LayoutMargin中对应的左内边距为100)
3.设置自动布局约束的时候,一定要设置Margin相关的约束(iOS8以上有效)

typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
   ...
    
    NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    
};

思考

现在基本上弄清楚了,LayoutMargin和preservesSuperviewLayoutMargins属性,以及如何使用,但是对他们在自动布局的实际使用场景还是没有思考太清楚,没有明白苹果为什么会设置这两个属性,特别是preservesSuperviewLayoutMargins属性。 = =

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,941评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,397评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,345评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,851评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,868评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,688评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,414评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,319评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,775评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,945评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,096评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,789评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,437评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,993评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,107评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,308评论 3 372
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,037评论 2 355

推荐阅读更多精彩内容