美文网首页
iOS ~ Auto Layout

iOS ~ Auto Layout

作者: 派大星的博客 | 来源:发表于2019-03-14 18:23 被阅读0次

参考文档

自从iPhoneX有了小刘海,iOS的布局就多了个绕不开话题--safeArea

safeAreaLayoutGuide反映该视图中没有被 navigation bars,tab bars, toolbars 和 其他祖先视图 遮盖的部分

safeAreaLayoutGuide

UIView的一个只读属性,#available(iOS 11.0, *),用来帮助你避免与系统元素重叠。

When the view is visible onscreen, this guide reflects the portion of the view that is not covered by navigation bars, tab bars, toolbars, and other ancestor views.

  • 当视图在屏幕上可见时,safeAreaLayoutGuide反映该视图中没有被 navigation bars, tab bars, toolbars 和 其他祖先视图 遮盖的部分。

注意⚠️:即使这些视图是部分透明的,它们仍然会遮挡它们下面的内容。

// 设置 navigationBar 为透明的,safeAreaLayoutGuide也为上图右
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
  • Status Bar 对于iPhone 8及以下的影响如下图:

    image.png
  • 允许横屏时


    image.png

safeAreaInsets

也是只读属性,是Frame布局是的选择。

iPhone X竖屏时占满整个屏幕的控制器的view的safeAreaInsets是(44,0,34,0),横屏是(0,44,21,44)


参考文档 : NSLayoutAnchor

一、 Auto Layout 进化过程

Auto Layout 的核心就是 “约束” —— NSLayoutConstraint

1⃣️: VFL语言

VFL全称是Visual Format Language,翻译过来是“可视化格式语言”

举个例子🌰: @"H:|-20-[blueView]-20-|"

// 来个代码看一下
- (void)viewDidLoad{
    [super viewDidLoad];
    UIView *redView = [[UIView alloc]init]; 
    redView.backgroundColor = [UIColor redColor]; 
    redView.translatesAutoresizingMaskIntoConstraints= NO;
    [self.view addSubview:redView];
    UIView *blueView = [[UIView alloc]init];
    blueView.backgroundColor = [UIColor blueColor];
    blueView.translatesAutoresizingMaskIntoConstraints= NO;
    [self.view addSubview:blueView];
   //水平方向
    NSString *hVFL=@"H:|-20-[redView]-30-[blueView(==redView)]-20-|";
    NSArray *hCons =[NSLayoutConstraint constraintsWithVisualFormat:hVFL options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:@{@"redView":redView,@"blueView":blueView}];
    [self.view addConstraints:hCons];
    //垂直方向
    NSString *vVFL =@"V:|-20-[redView(50)]";
    NSArray *vCons =[NSLayoutConstraint constraintsWithVisualFormat:vVFL options:0 metrics:nil views:@{@"redView":redView}];
    [self.view addConstraints:vCons];
}

缺点:

  1. 约束越复杂,越难描述;
  2. 字符串越长,越容易出错;
  3. 只能描述相对约束,不能描述绝对约束(例如有视图A和B,可以表示A的宽是B的两倍,但无法表示A的宽是100pt)。
2⃣️:NSLayoutConstraint

来段代码体验一下:

// Creating constraints using NSLayoutConstraint
NSLayoutConstraint(item: subview,
                   attribute: .leading,
                   relatedBy: .equal,
                   toItem: view,
                   attribute: .leadingMargin,
                   multiplier: 1.0,
                   constant: 0.0).isActive = true

NSLayoutConstraint(item: subview,
                   attribute: .trailing,
                   relatedBy: .equal,
                   toItem: view,
                   attribute: .trailingMargin,
                   multiplier: 1.0,
                   constant: 0.0).isActive = true

缺点:

  • 参数太多了,写个UI耗时费力。
3⃣️:NSLayoutAnchor
// Creating the same constraints using Layout Anchors
let margins = view.layoutMarginsGuide

subview.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
subview.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true

相比较来说 NSLayoutAnchor 确实是目前Auto Layout最好的选择。


二、LayoutAnchor 布局入门

布局属性分为3类:

  • NSLayoutDimension(尺寸)
    宽高(widthAnchor/heightAnchor)

  • NSLayoutXAxisAnchor(水平方向,x轴)
    左右(leftAnchor/rightAnchor),
    前后(leadingAnchor/trailingAnchor),
    水平中心(centerXAnchor)

  • NSLayoutYAxisAnchor(垂直方向,y轴)
    上下(topAnchor/bottomAnchor),
    垂直中心(centerYAnchor),
    上下基准线(firstBaselineAnchor/lastBaselineAnchor)

        let imageView = UIImageView()
        imageView.image = UIImage(named: "LoginDejaIcon")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(imageView)
        imageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
        imageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
        imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        if #available(iOS 11.0, *) {
            imageView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: -3).isActive = true
        } else {
            imageView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 47).isActive = true
        }

重点解析:

  • translatesAutoresizingMaskIntoConstraints
屏幕快照 2019-03-14 下午5.25.58.png

这个属性的意思也非常明显:就是把老式的AutoResizing(指 frame、bounds、center 和 autoresizingMask)自动转化为约束。

因为日常都是手写UI(Not Xib), translatesAutoresizingMaskIntoConstraints (by default is true)

如要对一个View进行Auto Layout的布局时(如上文code)需要把给属性设为 false。因为老式的AutoResizing的约束已经非常充分完全,再添加任何的约束都会导致冲突。

注意⚠️: translatesAutoresizingMaskIntoConstraints 其实是AutoResizingAutoLayout 鱼与熊掌兼的桥梁, 既在你的代码里,既可以存在 :

imageView1.frame = CGRect(x: 0, y: 0, width: 80, height: 80)

亦可以存在 :

imageView2.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 47).isActive = true

只是不能作用于 同一个View。


  • isActive
    The receiver may be activated or deactivated by manipulating this property. Only active constraints affect the calculated layout. Attempting to activate a constraint whose items have no common ancestor will cause an exception to be thrown. Defaults to NO for newly created constraints.

默认为false,需要设置为true才能激活约束属性。

有两个便捷方法激活和使无效

    /* Convenience method that activates each constraint in the contained array, in the same manner as setting active=YES. This is often more efficient than activating each constraint individually. */
    @available(iOS 8.0, *)
    open class func activate(_ constraints: [NSLayoutConstraint])

    
    /* Convenience method that deactivates each constraint in the contained array, in the same manner as setting active=NO. This is often more efficient than deactivating each constraint individually. */
    @available(iOS 8.0, *)
    open class func deactivate(_ constraints: [NSLayoutConstraint])

举例如下:

            NSLayoutConstraint.activate([
                bottomView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                bottomView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                bottomView.heightAnchor.constraint(equalToConstant: CGFloat(kFunctionPanelHeight)),
                bottomView.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor)
                ])

赠品:

  • autoresizingMask


    屏幕快照 2019-03-14 下午5.47.41.png

none:表示不随父视图的改变而改变
flexibleLeftMargin:表示随着父视图的改变自动调整view与父视图的左边距,保证view与父视图的右边距不变;
flexibleRightMargin:表示随着父视图的改变自动调整view与父视图的右边距,保证view与父视图的左边距不变;
flexibleTopMargin:表示随着父视图的改变自动调整view与父视图的上边距,保证下边距不变;
flexibleBottomMargin:表示随着父视图的改变自动调整view与父视图的下边距,保证上边距不变;
flexibleWidth:表示随着父视图的改变自动调整view的宽度,保证view与父视图左右边距不变;
flexibleHeight:表示随着父视图的改变自动调整view的高度,保证view与父视图的上下边距不变;

🌰:如此使用

self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

相关文章

网友评论

      本文标题:iOS ~ Auto Layout

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