【问题标题】:Centering view with visual format NSLayoutConstraints具有视觉格式 NSLayoutConstraints 的居中视图
【发布时间】:2013-11-29 23:57:07
【问题描述】:

我正在尝试使用视觉格式语言使视图居中。

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_progressView(300)]-|" options:NSLayoutFormatAlignAllCenterY metrics:0 views:views]];

views 是一个包含_progressViewNSDictionaryOfVariableBindings

它不会在self.view(宽度:768)内将我的视图(宽度:300)居中。它以 8 像素的边距将其向左对齐,就好像我只会写 @"H:|-[_progressView(300)"

是使用类似以下方法使视图居中的唯一方法:?

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];

谢谢

【问题讨论】:

    标签: objective-c ios7 autolayout nslayoutconstraint


    【解决方案1】:

    这个格式字符串

    @"H:|-[_progressView(300)]-|"
    

    不会告诉 AutoLayout 将 progressView 居中。相反,它说progressView 应该是 300 宽,并且在父视图边缘的任一侧都有系统定义的标准边距。显然这不能满足,所以 Auto Layout 放弃了一些约束(你可能会在控制台上得到一些日志)。在您的情况下删除的约束可能是右侧的边距。

    要真正在它的超级视图中居中视图,您必须使用详细约束方法而不是可视字符串格式,正如您已经发现的那样。但是,您可以轻松地将其归入一个不错的类别,如下所示:

    @interface UIView (MyLayout)
    - (void)centerHorizontallyInSuperview;
    @end
    
    @implementation UIView (MyLayout)
    - (void)centerHorizontallyInSuperview {
        NSLayoutConstraint *c;
        c = [NSLayoutConstraint constraintWithItem:self
                                         attribute:NSLayoutAttributeCenterX
                                         relatedBy:NSLayoutRelationEqual                                                             
                                            toItem:self.superview
                                         attribute:NSLayoutAttributeCenterX 
                                        multiplier:1 
                                          constant:0];
        [self.superview addConstraint:c];
    }
    @end
    

    【讨论】:

      【解决方案2】:

      三种方法:

      1. 您可以按照 DrummerB 的建议将约束添加代码放在方法或类别中。

        您还可以在 iOS 9 中使用更新、更简洁的语法,使用锚点和 activateConstraints

        [NSLayoutConstraint activateConstraints:@[
            [centerView.centerXAnchor constraintEqualToAnchor:view.centerXAnchor],
            ...
        ]];
        

        或者在 Swift 3 中:

        NSLayoutConstraint.activate([
            centerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            ...
        ])
        
      2. 你可以使用UILayoutGuide对象:

        UILayoutGuide *leftGuide = [[UILayoutGuide alloc] init];
        [view addLayoutGuide:leftGuide];
        UILayoutGuide *rightGuide = [[UILayoutGuide alloc] init];
        [view addLayoutGuide:rightGuide];
        

        并使用 VFL 将它们定义为彼此相等,如下所示:

        H:|[leftGuide][_progressView(==300)][rightGuide(==leftGuide)]|
        

        如果您不能使用布局指南(例如,您需要支持 9.0 之前的 iOS 版本,您想在 IB 中创建它等)您可以使用不可见的UIView 对象(alpha 为零或背景清晰的颜色)以非常相似的方式。只需将这些“间隔”视图添加到您的视图层次结构中,使用上面的水平约束,但只需配置视图以便您看不到它们。

        这种技术将是解决“如何使视图居中”问题的一种繁琐的方法,但如果您想要均匀地间隔十几个视图并且您不能使用UIStackView,则非常有用因为某些原因。您可以使用任意数量的UILayoutGuide(或不可见的UIView)对象来达到所需的效果。

      3. 为了完整起见,我应该指出,使用NSLayoutFormatAlignAllCenterX/Yoptions 可以达到效果,如https://stackoverflow.com/a/14917695/1271826 中所述,但我承认我发现造成不必要的混乱。

      就个人而言,我认为第一种方法最适合您的场景。第二种方法在尝试均匀分布一堆控件时很有用,但对于这个简单的场景来说太笨拙了。第三种方法是出于求知欲,但我不建议在任何实际应用中使用它。

      【讨论】:

      • 尽管我最喜欢类别解决方案最适合我当前的问题,但间隔解决方案在分隔多个项目时非常有用。我对你的回答投了赞成票。
      • 很好的选择总结。 1. 你的第二个。只有在 centeredView 旁边没有任何东西时,解决方案才是好的。正确的?并创建一个 clearView 我应该将它们的 alpha 设置为0? 2.你能解释一下(<=0)在做什么吗?
      • @Honey - 不,如果您在居中视图旁边有任何东西,第二种技术效果很好,只是您可能有单独的 VFL 用于视图的居中,另一个用于放置任何东西旁边它。而且,是的,要使视图“清晰”,只需将其背景设置为 clearColor 或降低其 alpha。或者现在,您通常会改用NSLayoutGuide,这样会好得多。关于第三种方法中的>= 语法,虽然我最初发现第三种方法在智力上很有趣,但回想起来,我不建议在它上面浪费任何时间。这是可怕的模式。
      【解决方案3】:

      对于那些需要它的人,@DrummerB 的 ObjC 类别作为 Swift 扩展:

      extension UIView {
      
          func centerInSuperview() {
              self.centerHorizontallyInSuperview()
              self.centerVerticallyInSuperview()
          }
      
          func centerHorizontallyInSuperview(){
              let c: NSLayoutConstraint = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: self.superview, attribute: .CenterX, multiplier: 1, constant: 0)
              self.superview?.addConstraint(c)
          }
      
          func centerVerticallyInSuperview(){
              let c: NSLayoutConstraint = NSLayoutConstraint(item: self, attribute: .CenterY, relatedBy: .Equal, toItem: self.superview, attribute: .CenterY, multiplier: 1, constant: 0)
              self.superview?.addConstraint(c)
          }
      
      }
      

      【讨论】:

      • 我会赞成,但请尝试将其保留给我尝试过并且知道有效的代码。所以我只想说谢谢你发布这个。
      • 绝对漂亮又方便!
      猜你喜欢
      • 2019-02-08
      • 2016-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-18
      相关资源
      最近更新 更多