如何以编程方式使用自动布局将活动指示器定位到其超级视图的中心?

Posted

技术标签:

【中文标题】如何以编程方式使用自动布局将活动指示器定位到其超级视图的中心?【英文标题】:How to position activity indicator to the center of its superview using Auto Layout programmatically? 【发布时间】:2013-10-17 15:43:19 【问题描述】:

为什么以下代码无法将活动指示器定位到其父视图的中心:

UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]
       initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];

[self.mysuperview addSubview:activityIndicator];
[activityIndicator addConstraints:[NSLayoutConstraint 
                   constraintsWithVisualFormat:@"|-(>=20)-[view(==100)]-(>=20)-|"
                   options:NSLayoutFormatAlignAllCenterX | NSLayoutFormatAlignAllCenterY
                   metrics:nil
                   views:@@"view" : self.mysuperview]];

活动指示器位于左上角的某处,绝对不在中心。

================== 更新: 找到的解决方案:我必须在创建指标后关闭自动调整大小约束,然后关闭所有给定工作的解决方案:

 [activityIndicator setTranslatesAutoresizingMaskIntoConstraints:NO];

我在@Vignesh 提供的链接上找到了它,所以我接受他/她的回答。

【问题讨论】:

有关信息,如果您使用github.com/dkduck/FLKAutoLayout,那么它也会为您处理。 我更喜欢github.com/Masonry/Masonry 是的。它对我来说也是 translatesAutoresizingMaskIntoConstraints。容易忘记。 天哪,我遇到了同样的错误。 请参阅my answer,它提供了使用 Auto Layout 或 Spring 和 Struts 解决问题的 4 种不同方法。 【参考方案1】:

以下四个 Swift 5 / ios 12 代码示例展示了如何使用自动布局UIActivityIndicatorView 居中在UIViewControllerUIView 中。

所有样品产生相同的结果,但根据您的需要和口味,您可以选择其中一种。

如果您的UIActivityIndicatorView 的超级视图不是self.view,您只需将每个self.view 调用替换为您自己的(未包装的)superview


1。 NSLayoutConstraint 初始化样式

import UIKit

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        let indicatorView = UIActivityIndicatorView(style: .gray)
        indicatorView.isHidden = false
        indicatorView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(indicatorView)

        // Auto layout
        let horizontalConstraint = NSLayoutConstraint(item: indicatorView,
                                                      attribute: .centerX,
                                                      relatedBy: .equal,
                                                      toItem: self.view,
                                                      attribute: .centerX,
                                                      multiplier: 1,
                                                      constant: 0)
        let verticalConstraint = NSLayoutConstraint(item: indicatorView,
                                                    attribute: .centerY,
                                                    relatedBy: .equal,
                                                    toItem: self.view,
                                                    attribute: .centerY,
                                                    multiplier: 1,
                                                    constant: 0)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
        /*
         // You can replace NSLayoutConstraint activate(_:) call with the following lines:
         self.view.addConstraint(horizontalConstraint)
         self.view.addConstraint(verticalConstraint)
         */
    



2。 UIViewAutoresizing风格

Springs 和 Struts 会在运行时翻译成相应的自动布局约束。

import UIKit

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        let indicatorView = UIActivityIndicatorView(style: .gray)
        indicatorView.isHidden = false
        indicatorView.translatesAutoresizingMaskIntoConstraints = true // default is true
        self.view.addSubview(indicatorView)

        // Springs and struts
        indicatorView.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.midY)
        indicatorView.autoresizingMask = [
            .flexibleLeftMargin,
            .flexibleRightMargin,
            .flexibleTopMargin,
            .flexibleBottomMargin
        ]
    



3。视觉格式语言风格

import UIKit

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        let indicatorView = UIActivityIndicatorView(style: .gray)
        indicatorView.isHidden = false
        indicatorView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(indicatorView)

        // Auto layout
        let views = ["superview": self.view!, "indicatorView": indicatorView]
        let horizontalConstraints = NSLayoutConstraint
            .constraints(withVisualFormat: "H:[superview]-(<=0)-[indicatorView]",
                         options: .alignAllCenterY,
                         metrics: nil,
                         views: views)
        let verticalConstraints = NSLayoutConstraint
            .constraints(withVisualFormat: "V:[superview]-(<=0)-[indicatorView]",
                         options: .alignAllCenterX,
                         metrics: nil,
                         views: views)
        self.view.addConstraints(horizontalConstraints)
        self.view.addConstraints(verticalConstraints)
    



4。 NSLayoutAnchor 样式(需要 iOS 9)

import UIKit

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        let indicatorView = UIActivityIndicatorView(style: .gray)
        indicatorView.isHidden = false
        indicatorView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(indicatorView)

        // Auto layout
        let horizontalConstraint = indicatorView
            .centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
        let verticalConstraint = indicatorView
            .centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
        /*
         // You can replace NSLayoutConstraint activate(_:) call with the following lines:
         self.view.addConstraint(horizontalConstraint)
         self.view.addConstraint(verticalConstraint)
         */
    


【讨论】:

视觉格式语言风格对我有用!谢谢@Imanou Petit【参考方案2】:

它在角落里满足了它的要求,因为你并不是说两边的间隙必须相同。试试这个:

[self.superview addConstraint:[NSLayoutConstraint constraintWithItem:activityIndicator
               attribute:NSLayoutAttributeCenterX 
               relatedBy:NSLayoutRelationEqual 
                  toItem:self.superview 
               attribute:NSLayoutAttributeCenterX 
              multiplier:1.0 
                constant:0.0]];

垂直居中也可以这样做:

[self.superview addConstraint:[NSLayoutConstraint constraintWithItem:activityIndicator
               attribute:NSLayoutAttributeCenterY 
               relatedBy:NSLayoutRelationEqual 
                  toItem:self.superview 
               attribute:NSLayoutAttributeCenterY 
              multiplier:1.0 
                constant:0.0]];

另外,我强烈建议使用 FLKAutoLayout 项目来简化这一切:

https://github.com/dkduck/FLKAutoLayout

那么你可以这样做:

[activityIndicator alignCenterXWithView:self.superview predicate:nil];
[activityIndicator alignCenterYWithView:self.superview predicate:nil];

这很好:)

【讨论】:

如果您希望它位于中心,您还需要添加CenterY。只有 X 可以是父视图中间垂直线上的任意位置。 是的,但是海报的代码只是试图水平居中,所以我认为这是要求......不过我会更新...... 啊,对不起,我没有意识到这一点。 我实际上需要水平和垂直居中。我不知道我做错了什么,但不知何故这个解决方案也不起作用。 检查它们是否有共同的超级视图。【参考方案3】:

你可以试试这个,

 UIView *superview = self.mysuperview;
NSDictionary *variables = NSDictionaryOfVariableBindings(activityIndicator, superview);
NSArray *constraints =
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[superview]-(<=1)-[activityIndicator]"
                                        options: NSLayoutFormatAlignAllCenterX
                                        metrics:nil
                                          views:variables];
[self.view addConstraints:constraints];

constraints =
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[superview]-(<=1)-[activityIndicator]"
                                        options: NSLayoutFormatAlignAllCenterY
                                        metrics:nil
                                          views:variables];
[self.view addConstraints:constraints];

取自here。

【讨论】:

感谢您的链接,它帮助我找到了答案。解决方法是[activityIndi​​cator setTranslatesAutoresizingMaskIntoConstraints:NO];【参考方案4】:

我通过在 Interface Builder 中添加一个 alpha 为零的活动指示器(并在我的视图控制器类中为它添加一个 IBOutlet),使我的活动指示器在其超级视图中居中。然后我添加了约束使其在 X 和 Y 轴上居中。最后,我为其添加了宽度和高度约束以消除自动布局错误。

在我的视图控制器的 startActivityIndi​​cator 方法中,我将活动指示器的 alpha 设置为 1 并在其上调用 startAnimating 方法。在我的 stopActivityIndi​​cator 方法中,我对其调用 stopAnimating 方法并将活动指示器的 alpha 设置回零。

【讨论】:

以上是关于如何以编程方式使用自动布局将活动指示器定位到其超级视图的中心?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式将 UIView 粘贴到其超级视图的右侧

如何以编程方式添加标签并以编程方式使用自动布局定位它

以编程方式从超级视图中删除视图后更新约束/框架(自动布局)

自动布局 - 以编程方式定义异常约束

iOS - 以编程方式在具有自动布局的 UITextField 内定位 UIImageView

使用自动布局的屏幕外 UIView(以编程方式)