笔记: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阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容