使用尺寸类别以编程方式实现两种不同的布局

问题描述 投票:0回答:4

我有四个按钮布局。在肖像中,它们应该一个在另一个之上。在横向中,它们应该分为两列,每列有两个按钮。

我在代码中实现了按钮 - 非常简单的东西:

UIButton *btn1 = [[UIButton alloc] init];
[self.view addSubview: btn1]; 

UIButton *btn2 = [[UIButton alloc] init];
[self.view addSubview: btn2]; 

UIButton *btn3 = [[UIButton alloc] init];
[self.view addSubview: btn3]; 

UIButton *btn4 = [[UIButton alloc] init];
[self.view addSubview: btn4]; 

NSDictionary *views = NSDictionaryOfVariableBindings(btn1, btn2, btn3, btn4);

[btn1 setTranslatesAutoresizingMaskIntoConstraints:NO];
[btn2 setTranslatesAutoresizingMaskIntoConstraints:NO];
[btn3 setTranslatesAutoresizingMaskIntoConstraints:NO];
[btn4 setTranslatesAutoresizingMaskIntoConstraints:NO];

// portrait constraints
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn1]-(50)-|"
                                                                 options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn2]-(50)-|"
                                                                 options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn3]-(50)-|"
                                                                 options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[btn4]-(50)-|"
                                                                 options:0 metrics:nil views:views]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[btn1]-[btn2]-[btn3]-[btn4]-(50)-|"
                                                                 options:0 metrics:nil views:views]];

这显然是纵向布局的设置。我本来会确定设备及其方向,以便为 iPad 和 iPhone 各自的方向制作特定的外壳。但现在我们应该使用尺寸类别。如何确定尺寸类别是否为“紧凑”...从而设置适当的约束?

objective-c autolayout ios8 size-classes
4个回答
56
投票

同时我找到了一个很好的解决方案。由于这个问题得到了如此多的支持,我想我应该快速描述一下。我受到 WWDC 会议的启发而想到了这个解决方案。

我已经转向 Swift,所以请原谅代码将使用 Swift 语言 - 然而 Obj-C 的概念是相同的。

首先声明三个约束数组:

 // Constraints
 private var compactConstraints: [NSLayoutConstraint] = []
 private var regularConstraints: [NSLayoutConstraint] = []
 private var sharedConstraints: [NSLayoutConstraint] = []

然后你相应地填写约束条件。也就是说,您可以在从

viewDidLoad
调用的单独函数中执行此操作,或者直接在
viewDidLoad
中执行此操作。

sharedConstraints.append(contentsOf: [
     btnStackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
    ...
])

compactConstraints.append(contentsOf: [
     btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.7),
    ...
])

regularConstraints.append(contentsOf: [
     btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.4),
    ...
])

重要的部分是在尺寸类别之间切换并激活/停用适当的约束。

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {

    super.traitCollectionDidChange(previousTraitCollection)

    if (!sharedConstraints[0].isActive) {
       // activating shared constraints
       NSLayoutConstraint.activate(sharedConstraints)
    }


    if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular {
        if regularConstraints.count > 0 && regularConstraints[0].isActive {
            NSLayoutConstraint.deactivate(regularConstraints)
        }
        // activating compact constraints
        NSLayoutConstraint.activate(compactConstraints)
    } else {
        if compactConstraints.count > 0 && compactConstraints[0].isActive {
            NSLayoutConstraint.deactivate(compactConstraints)
        }
        // activating regular constraints
        NSLayoutConstraint.activate(regularConstraints)
    }
}

我知道这些限制与问题中的限制不符。但约束本身是无关紧要的。最主要的是如何根据尺寸类别在两组约束之间进行切换。

希望这有帮助。


42
投票

您可以检查视图的特征集合以确定其水平和垂直尺寸类别。

if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
    ...
}

实现

traitCollectionDidChange:
方法,当特征因自转而发生变化时自动调用。

有关更多信息,请参阅 UITraitCollection 类参考UITraitEnvironment 协议参考


11
投票

已接受答案的 Swift 4 代码:

if (self.view.traitCollection.horizontalSizeClass == .compact) {
...
}

2
投票

traitCollection 仅适用于 iOS8。所以你的应用程序将在 iOS7 上崩溃。使用下面的代码同时支持iOS7和iOS8

if ([self.view respondsToSelector:@selector(traitCollection)]){

    if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
    ...
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.