美文网首页
关于自动布局的那点事儿NSLayoutConstraint VF

关于自动布局的那点事儿NSLayoutConstraint VF

作者: Mark_Guan | 来源:发表于2016-12-20 15:14 被阅读77次
  1. NSLayoutConstraint
  2. VFL
  3. Masonry

在开发中我们经常会将XIB、StoryBoard配合AutoLayout 来完成界面的适配,但是很多时候如果我们需要封装一个库却不想在库中使用XIB或者StoryBoard,此时我们就需要通过纯代码的方式来对屏幕进行适配了,这也是今天我想讲的主要内容,即 如何用纯代码的方式来进行屏幕适配

NSLayoutConstraint

我们先说一下使用 NSLayoutConstraint的具体步骤:

  • 利用 NSLayoutConstraint 类创建具体的约束对象,注意一个 NSLayoutConstraint实例代表一条约束。
  • 添加约束对象到相应的 view 上,苹果为我们提供了两个方法:
- (void)addConstraint:(NSLayoutConstraint *)constraint NS_AVAILABLE_IOS(6_0);
- (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints NS_AVAILABLE_IOS(6_0);

下面我们来看一个具体的例子:
NSLayoutConstraint实现一个宽度高度为100,在父控件中垂直水平居中的效果

     UIView *redView = [[UIView alloc] init];
   redView.backgroundColor = [UIColor redColor];
   [self.view addSubview:redView];
   
   //要先禁止 autoresizing 功能
   redView.translatesAutoresizingMaskIntoConstraints = NO;
   
   /**
    *参数一:要约束的控件
    *参数二:约束的类型(做怎样的约束)
    *参数三:与参照控件之间的关系
    *参数四:参照的控件
    *参数五:约束的类型(做怎样的约束)
    *参数六:乘数
    *参数七:常量
    */
    // 添加宽度约束:父控件的一半
   NSLayoutConstraint *consW = [NSLayoutConstraint constraintWithItem:redView
                                                   attribute:NSLayoutAttributeWidth
                                                   relatedBy:NSLayoutRelationEqual
                                                   toItem:self.view
                                                   attribute:NSLayoutAttributeWidth
                                                   multiplier:0.5
                                                   constant:0.0
                                ];
   // 添加高度约束:父控件的一半
   NSLayoutConstraint *consH = [NSLayoutConstraint constraintWithItem:redView
                                                   attribute:NSLayoutAttributeHeight
                                                   relatedBy:NSLayoutRelationEqual
                                                   toItem:self.view attribute:NSLayoutAttributeHeight
                                                   multiplier:0.5
                                                   constant:0.0
                                ];
   // 水平居中
   NSLayoutConstraint *consX = [NSLayoutConstraint constraintWithItem:redView
                                                   attribute:NSLayoutAttributeCenterX
                                                   relatedBy:NSLayoutRelationEqual
                                                   toItem:self.view
                                                   attribute:NSLayoutAttributeCenterX
                                                   multiplier:1.0
                                                   constant:0.0
                                      ];
   // 垂直居中
   NSLayoutConstraint *consY = [NSLayoutConstraint constraintWithItem:redView
                                                   attribute:NSLayoutAttributeCenterY
                                                   relatedBy:NSLayoutRelationEqual
                                                   toItem:self.view
                                                   attribute:NSLayoutAttributeCenterY
                                                   multiplier:1.0
                                                   constant:0.0
                                        ];
   
   [self.view addConstraints:@[consW,consH,consX,consY]];

效果图如下:

image

注意事项

  1. 要先禁止 autoresizing 功能 redView.translatesAutoresizingMaskIntoConstraints = NO;
  2. 添加约束之前,一定要保证相关控件都已经添加到对应的父控件上了
  3. 因为iOS中原点在左上角所以使用offset时注意right和bottom用负数

添加约束的规则
在创建约束之后,需要将其添加到作用的view上,在添加时要注意目标view需要遵循以下规则:

  1. 对于两个同层级view之间的约束关系,添加到它们的父view上 image
  2. 对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上 image
  3. 对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上 image

VFL(Visual Format Language)

通过上面宽高为100,在父控件中垂直水平居中的简单效果可以看到复杂程度,苹果公司为了简化这种操作,设计了一种 可视化格式语言即:VFL

VFL的思想其实很简单,它将约束分成了两块即水平方向(H:)和垂直方向(V:)

其实苹果官方文档对 这一块 描述的特别详细,这里我就直接贴图了:


宽度约束 image
image
image

我们来看看官方为我们提供的API

/**
 *  参数一:format     VFL格式构成的字符串,用以表达想要添加的约束
 *  参数二:options    对齐方式,是一个枚举值
 *  参数三:metrics    一般传入以间距为KEY的字典,如: @{ @"margin":@20},KEY要与format参数里所填写的“margin”相同
 *  参数三:views      传入约束中提到的View,也是要传入字典,但是KEY一定要和format参数里所填写的View名字相同
 *
 *  @return 返回约束的数组
 */
+ (NSArray *)constraintsWithVisualFormat:(NSString *)format
                                 options:(NSLayoutFormatOptions)options
                                 metrics:(NSDictionary *)metrics
                                 views:(NSDictionary *)views;

注意:
因为参数三和参数四需要传入字典,字典的KEY要和Format中的名字相同,如果我们自己去写 第一比较麻烦,第二不小心还容易写错,所以苹果为我们提供了一个强大的: NSDictionaryOfVariableBindings

/* This macro is a helper for making view dictionaries 
for +constraintsWithVisualFormat:options:metrics:views: 
 NSDictionaryOfVariableBindings(v1, v2, v3) is equivalent to 
 [NSDictionary dictionaryWithObjectsAndKeys:v1, @"v1", v2, @"v2", v3, @"v3", nil];
 */
#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)

为了更清晰的展示VFL的用法 下面我用一个例子来展示一下:
🌰例子:用VFL实现下面的效果:View宽高相等,边距20

image
      UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = [UIColor blueColor];
    // 不要将AutoresizingMask转为Autolayout的约束
    blueView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:blueView];
    
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    // 不要将AutoresizingMask转为Autolayout的约束
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:redView];
    
    // 间距
    NSNumber *margin = @20;
    
    // 添加水平方向的约束
    NSString *hFormat = @"H:|-margin-[blueView]-margin-[redView(==blueView)]-margin-|";
    
    //把要添加约束的View转成字典
    NSDictionary *views = NSDictionaryOfVariableBindings(blueView, redView);
    NSDictionary *mertrics = NSDictionaryOfVariableBindings(margin);
    //options: 这里设置底部和顶部对齐
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:hFormat
                                               options:NSLayoutFormatAlignAllTop
                                                     | NSLayoutFormatAlignAllBottom
                                                metrics:mertrics
                                                views:views];
    [self.view addConstraints:constraints];
    
    // 添加竖直方向的间距
    NSNumber *height = @40;
    NSString *vFormat = @"V:[blueView(height)]-margin-|";
    NSDictionary *mertrics2 = NSDictionaryOfVariableBindings(margin, height);
    NSArray *constraints2 = [NSLayoutConstraint constraintsWithVisualFormat:vFormat
                                                options:kNilOptions
                                                metrics:mertrics2
                                                views:views];
    [self.view addConstraints:constraints2];

VFL也是有缺陷的,这话是苹果自己说的 有图有真相

image
所以 这也就引出了下面我想讲的东西 Masonry

Masonry

其实关于Masonry的用法 其github上的主页已经描述的非常清楚直白了,这里我们直接用Masonry来实现最开始的小例子

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
    
    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.size.equalTo(self.view).multipliedBy(0.5);
        make.center.equalTo(self.view);//make centerX and centerY = self.view
    }];
    

是不是Soeasy.....代码量简单了很多?

比如我们想实现一个控件 距离其父控件上下左右都为10的效果:

NSInteger padding = 10;
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(padding);
}];

是不是爽爆了....
更多更详细的信息可以去其官方文档上查看

相关文章

网友评论

      本文标题:关于自动布局的那点事儿NSLayoutConstraint VF

      本文链接:https://www.haomeiwen.com/subject/aqzxvttx.html