筆記:NSLayoutAnchor方式進行自動布局

大多數情況下,我們都是使用Masonry這個三方庫來進行約束布局,其實蘋果開放的NSLayoutAnchor來布局也很方便,他跟Masonry一樣底層都是通過NSLayoutConstraint來實現的,因此備份一個UIView的布局擴展代碼筆記。

UIView擴展

UIView+GLLayout.h


#import <UIKit/UIKit.h>

/// layout布局
typedef enum : NSUInteger {
    GLLayoutTypeLeft = 0,
    GLLayoutTypeRight,
    GLLayoutTypeTop,
    GLLayoutTypeBottom,
    GLLayoutTypeCenterX,
    GLLayoutTypeCenterY,
    GLLayoutTypeRealLeft,
    GLLayoutTypeRealRight,
    GLLayoutTypeWidth,
    GLLayoutTypeHeight,
} GLLayoutType;

@interface UIView (GLLayout)

// MARK: - 寬
/// 寬度
- (void)gl_width:(CGFloat)width;

/// 寬度=view
- (void)gl_widthByView:(UIView *)view;

/// 寬度=view+offset
- (void)gl_widthByView:(UIView *)view offset:(CGFloat)offset;

/// 寬度=view*multiplier
- (void)gl_widthByView:(UIView *)view multiplier:(CGFloat)multiplier;

///寬度=view.direction + offset
- (void)gl_widthByView:(UIView *)view offset:(CGFloat)offset viewDirection:(GLLayoutType)direction ;

// MARK: - 高
/// 高度
- (void)gl_height:(CGFloat)height;

/// 高度=view
- (void)gl_heightByView:(UIView *)view;

/// 高度=view+offset
- (void)gl_heightByView:(UIView *)view offset:(CGFloat)offset;

/// 高度=view*multiplier
- (void)gl_heightByView:(UIView *)view multiplier:(CGFloat)multiplier;
///高度=view.direction + offset
- (void)gl_heightByView:(UIView *)view offset:(CGFloat)offset viewDirection:(GLLayoutType)direction ;
// MARK: - left
/// left: 相對父視圖
- (void)gl_left:(CGFloat)left;

/// left: 偏移量      view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_left:(CGFloat)left byView:(UIView *)view viewDirection:(GLLayoutType)direction;

/// real_left: 相對父視圖  非RTL自動布局
- (void)gl_real_left:(CGFloat)real_left;

/// real_left: 偏移量      view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_real_left:(CGFloat)real_left byView:(UIView *)view viewDirection:(GLLayoutType)direction;


// MARK: - right
/// right: 相對父視圖
- (void)gl_right:(CGFloat)right;

/// right: 偏移量       view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_right:(CGFloat)right byView:(UIView *)view viewDirection:(GLLayoutType)direction;

/// real_right: 相對父視圖
- (void)gl_real_right:(CGFloat)real_right;

/// real_right: 偏移量       view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_real_right:(CGFloat)real_right byView:(UIView *)view viewDirection:(GLLayoutType)direction;


// MARK: - top
/// top: 相對父視圖
- (void)gl_top:(CGFloat)top;

/// top: 偏移量       view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_top:(CGFloat)top byView:(UIView *)view viewDirection:(GLLayoutType)direction;


// MARK: - bottom
/// bottom: 相對父視圖
- (void)gl_bottom:(CGFloat)bottom;

/// bottom: 偏移量       view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_bottom:(CGFloat)bottom byView:(UIView *)view viewDirection:(GLLayoutType)direction;


// MARK: - centerX
/// centerX: 相對父視圖 0是默認父視圖居中
- (void)gl_centerX:(CGFloat)centerX;

/// centerX: 偏移量       view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_centerX:(CGFloat)centerX byView:(UIView *)view viewDirection:(GLLayoutType)direction;


// MARK: - centerY
/// centerY: 相對父視圖 0是默認父視圖居中
- (void)gl_centerY:(CGFloat)centerY;

/// centerY: 偏移量       view: 相對view    direction: 相對view的left / right / top / bottom...
- (void)gl_centerY:(CGFloat)centerY byView:(UIView *)view viewDirection:(GLLayoutType)direction;


@end


#import "UIView+GLLayout.h"

@implementation UIView (GLLayout)

- (void)removeConstraintWithType:(NSLayoutAttribute)type {
    //找出當前視圖對象的指定類型的約束對象
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstAttribute == %ld && firstItem == %@",type,self];
    //約束對象列表(width,height)
    NSArray *constantConstraints = [self.constraints filteredArrayUsingPredicate:predicate];
    if (constantConstraints.count > 0) {
        [self removeConstraints:constantConstraints];
    }
    //約束對象列表(left,right,too,bottom,centerX....)
    NSArray *anchorConstraints = [self.superview.constraints filteredArrayUsingPredicate:predicate];
    if (anchorConstraints) {
        [self.superview removeConstraints:anchorConstraints];
    }
}

// MARK: - 寬
- (void)gl_width:(CGFloat)width {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeWidth];
    [self.widthAnchor constraintEqualToConstant:width].active = YES;
}

- (void)gl_widthByView:(UIView *)view {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeWidth];
        [self.widthAnchor constraintEqualToAnchor:view.widthAnchor].active = YES;
    }
}

- (void)gl_widthByView:(UIView *)view offset:(CGFloat)offset {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeWidth];
        [self.widthAnchor constraintEqualToAnchor:view.widthAnchor constant:offset].active = YES;
    }
}

- (void)gl_widthByView:(UIView *)view offset:(CGFloat)offset viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeWidth];
        [self.widthAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction]  constant:offset].active = YES;
    }
}


- (void)gl_widthByView:(UIView *)view multiplier:(CGFloat)multiplier {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeWidth];
        [self.widthAnchor constraintEqualToAnchor:view.widthAnchor multiplier:multiplier].active = YES;
    }
}

// MARK: - 高
- (void)gl_height:(CGFloat)height {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeHeight];
    [self.heightAnchor constraintEqualToConstant:height].active = YES;
}

- (void)gl_heightByView:(UIView *)view {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeHeight];
        [self.heightAnchor constraintEqualToAnchor:view.heightAnchor].active = YES;
    }
}

- (void)gl_heightByView:(UIView *)view offset:(CGFloat)offset {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeHeight];
        [self.heightAnchor constraintEqualToAnchor:view.heightAnchor constant:offset].active = YES;
    }
}

- (void)gl_heightByView:(UIView *)view offset:(CGFloat)offset viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeHeight];
        [self.heightAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction]  constant:offset].active = YES;
    }
}


- (void)gl_heightByView:(UIView *)view multiplier:(CGFloat)multiplier {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    if (view) {
        [self removeConstraintWithType:NSLayoutAttributeHeight];
        [self.heightAnchor constraintEqualToAnchor:view.heightAnchor multiplier:multiplier].active = YES;
    }
}


// MARK: - left
- (void)gl_left:(CGFloat)left {
    [self gl_left:left byView:nil viewDirection:GLLayoutTypeLeft];
}

- (void)gl_left:(CGFloat)left byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeLeading];
    if (view) {
        [self.leadingAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:left].active = YES;
    }else {
        [self.leadingAnchor constraintEqualToAnchor:self.superview.leadingAnchor constant:left].active = YES;
    }
}

- (void)gl_real_left:(CGFloat)real_left {
    [self gl_real_left:real_left byView:nil viewDirection:GLLayoutTypeRealLeft];
}

- (void)gl_real_left:(CGFloat)real_left byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeLeft];
    if (view) {
        [self.leftAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:real_left].active = YES;
    }else {
        [self.leftAnchor constraintEqualToAnchor:self.superview.leftAnchor constant:real_left].active = YES;
    }
}

// MARK: - right
- (void)gl_right:(CGFloat)right {
    [self gl_right:right byView:nil viewDirection:GLLayoutTypeRight];
}

- (void)gl_right:(CGFloat)right byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeTrailing];
    if (view) {
        [self.trailingAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:-right].active = YES;
    }else {
        [self.trailingAnchor constraintEqualToAnchor:self.superview.trailingAnchor constant:-right].active = YES;
    }
}

- (void)gl_real_right:(CGFloat)real_right {
    [self gl_real_right:real_right byView:nil viewDirection:GLLayoutTypeRealRight];
}

- (void)gl_real_right:(CGFloat)real_right byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeRight];
    if (view) {
        [self.rightAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:-real_right].active = YES;
    }else {
        [self.rightAnchor constraintEqualToAnchor:self.superview.rightAnchor constant:-real_right].active = YES;
    }
}

// MARK: - top
- (void)gl_top:(CGFloat)top {
    [self gl_top:top byView:nil viewDirection:GLLayoutTypeTop];
}

- (void)gl_top:(CGFloat)top byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeTop];
    if (view) {
        [self.topAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:top].active = YES;
    }else {
        [self.topAnchor constraintEqualToAnchor:self.superview.topAnchor constant:top].active = YES;
    }
}

// MARK: - bottom
- (void)gl_bottom:(CGFloat)bottom {
    [self gl_bottom:bottom byView:nil viewDirection:GLLayoutTypeBottom];
}

- (void)gl_bottom:(CGFloat)bottom byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeBottom];
    if (view) {
        [self.bottomAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:-bottom].active = YES;
    }else {
        [self.bottomAnchor constraintEqualToAnchor:self.superview.bottomAnchor constant:-bottom].active = YES;
    }
}

// MARK: - centerX
- (void)gl_centerX:(CGFloat)centerX {
    [self gl_centerX:centerX byView:nil viewDirection:GLLayoutTypeCenterX];
}

- (void)gl_centerX:(CGFloat)centerX byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeCenterX];
    if (view) {
        [self.centerXAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:centerX].active = YES;
    }else {
        [self.centerXAnchor constraintEqualToAnchor:self.superview.centerXAnchor constant:centerX].active = YES;
    }
}

// MARK: - centerY
- (void)gl_centerY:(CGFloat)centerY {
    [self gl_centerY:centerY byView:nil viewDirection:GLLayoutTypeCenterY];
}

- (void)gl_centerY:(CGFloat)centerY byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    [self removeConstraintWithType:NSLayoutAttributeCenterY];
    if (view) {
        [self.centerYAnchor constraintEqualToAnchor:[self byView:view viewDirection:direction] constant:centerY].active = YES;
    }else {
        [self.centerYAnchor constraintEqualToAnchor:self.superview.centerYAnchor constant:centerY].active = YES;
    }
}

- (NSLayoutAnchor *)byView:(UIView *)view viewDirection:(GLLayoutType)direction {
    NSLayoutAnchor *anchor = nil;
    switch (direction) {
        case GLLayoutTypeTop:
            anchor = view.topAnchor;
            break;
        case GLLayoutTypeLeft:
            anchor = view.leadingAnchor;
            break;
        case GLLayoutTypeBottom:
            anchor = view.bottomAnchor;
            break;
        case GLLayoutTypeRight:
            anchor = view.trailingAnchor;
            break;
        case GLLayoutTypeCenterX:
            anchor = view.centerXAnchor;
            break;
        case GLLayoutTypeCenterY:
            anchor = view.centerYAnchor;
            break;
        case GLLayoutTypeRealLeft:
            anchor = view.leftAnchor;
            break;
        case GLLayoutTypeRealRight:
            anchor = view.rightAnchor;
            break;
        case GLLayoutTypeHeight:
            anchor = view.heightAnchor;
            break;
        case GLLayoutTypeWidth:
            anchor = view.widthAnchor;
            break;
        default:
            break;
    }
    return anchor;
}

@end

使用

    UIView *w = [UIView new];
    w.backgroundColor = [UIColor redColor];
    [self.view addSubview:w];
    
    //設置(設置和更新都是一個接口不會有代碼約束沖突)
    [w gl_top:100]; //更新top:[w gl_top:120];
    [w gl_left:100];
    [w gl_width:100];
    [w gl_height:100];
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容