LayoutMargin & preservesSuperviewLayoutMargins 學(xué)習(xí)筆記

發(fā)現(xiàn)問題

在IB中拖放tableView,大小為設(shè)置為屏幕大小后,添加了四個方向的約束,發(fā)現(xiàn),約束的值居然不是和想象中不太一樣,不是0。

1.png

接著打開attribute inspector,發(fā)現(xiàn)約束信息如下:


2.png

在這里發(fā)現(xiàn)Second Item是superView 的 leading Margin. 而不是superView的leading,所以約束的值不是0,但leading margin又是什么?

Layout Magrin

通過查找文檔,發(fā)現(xiàn)這是iOS 8 以后,UIView 新增的一個屬性,layoutMargins. 表示一個View的內(nèi)邊距。

文檔

@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設(shè)置子View布局的內(nèi)邊距。

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 是系統(tǒng)設(shè)置和控制的,不能修改。(文章最開始的tableView到 leading Margin 約束為 -16.就說明,left margin是16點。)

到這里,其實對layoutMargins理解都較為清晰,但是文檔中還提到了一個與layoutMargins 相關(guān)的屬性: 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值,決定當(dāng)前View布局是否也考慮父View的layoutMargins.
默認是NO.

到這里還是暈的,沒看懂這個屬性是干嘛,繼續(xù)看文檔。

文檔

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.

當(dāng)這個屬性是YES的時候,父view的layoutMargins會被考慮到當(dāng)前View的布局中。也就是說,當(dāng)前View和父View的內(nèi)邊距,小于父View相應(yīng)layoutMargins中對應(yīng)的內(nèi)邊距時,父View的內(nèi)邊距會決定當(dāng)前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一樣大的你設(shè)置了contentView的preservesSuperviewLayoutMargins為YES,當(dāng)你對contentView中的子View進行布局的時候,如果有子View的所在位置(比如:子View到contentView的左邊距,小于父View的LayoutMargin 對應(yīng)的左內(nèi)邊距)UIKit就會對子View進行一些調(diào)整。
感覺看了這一段稍微清晰了一些,可是寫代碼想實現(xiàn)一個demo的時候,發(fā)現(xiàn)這個preservesSuperviewLayoutMargins屬性好像并沒有什么卵用。
最后再Google上搜到了這篇文章。
iOS8 Day-by-Day :: Day 32 :: Layout Margins

然后自己實現(xiàn)了一個 demo 如下

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //創(chuàng)建一個紅色的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)]];
    
    //創(chuàng)建一個綠色的View,作為我們的ContentView,父View為紅色的View
    //約束為到紅色View各邊距為10,但紅色View 的layoutMargin 還是再綠色View內(nèi)
    //設(shè)置綠色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)]];
    
    //創(chuàng)建一個藍色View,作為綠色View的子View
    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = [UIColor blueColor];
    blueView.translatesAutoresizingMaskIntoConstraints = NO;
    [greenView addSubview:blueView];
    
    //注意,leading 約束對應(yīng)的第二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

總結(jié)

最后總結(jié)一下preservesSuperviewLayoutMargins生效的要點:(如果總結(jié)的不對希望大家指正~)
1.preservesSuperviewLayoutMargins 只在自動布局情況下生效
2.contentView(設(shè)置preservesSuperviewLayoutMargins的View)的父View的LayoutMargin中,至少存在contentView 某一個方向到父View的邊距,小于父View LayoutMargin 對應(yīng)的內(nèi)邊距。(就比如上面栗子中,綠色View到紅色View的左邊距是10,紅色View的LayoutMargin中對應(yīng)的左內(nèi)邊距為100)
3.設(shè)置自動布局約束的時候,一定要設(shè)置Margin相關(guān)的約束(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),
    
};

思考

現(xiàn)在基本上弄清楚了,LayoutMargin和preservesSuperviewLayoutMargins屬性,以及如何使用,但是對他們在自動布局的實際使用場景還是沒有思考太清楚,沒有明白蘋果為什么會設(shè)置這兩個屬性,特別是preservesSuperviewLayoutMargins屬性。 = =

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容