美文网首页
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