Подтвердить что ты не робот

Программная реализация двух разных макетов с использованием классов размера

У меня есть четыре кнопки. В портрете они должны быть показаны один над другим. В ландшафте они должны состоять из двух столбцов с двумя кнопками.

Я реализую кнопки в коде - очень простой материал:

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 в соответствующих направлениях. Но теперь мы должны использовать классы размеров. Как определить, является ли класс размера "компактным"... и, следовательно, установить соответствующие ограничения?

4b9b3361

Ответ 1

Тем временем я нашел хорошее решение. Поскольку у этого вопроса было так много проблем, я подумал, что быстро описал бы это. Я был вдохновлен этим решением на сессию WWDC.

Я перешел на 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)
    }
}

Я знаю, что ограничения не соответствуют тем, что в вопросе. Но сами ограничения не имеют значения. Главное, как переключаться между двумя наборами ограничений на основе класса размера.

Надеюсь, что это поможет.

Ответ 2

Вы можете просмотреть коллекцию свойств представления, чтобы определить ее горизонтальный и вертикальный размер.

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

Внедрить метод traitCollectionDidChange:, который будет автоматически вызываться, когда свойство изменяется из-за авторотации.

Для получения дополнительной информации см. Ссылка на класс UITraitCollection и UITraitEnvironment Protocol Reference.

Ответ 3

Swift 4 для принятого ответа:

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

Ответ 4

traitCollection работает только в iOS8. Таким образом ваше приложение будет разбиваться на iOS7. Используйте приведенный ниже код для поддержки iOS7 и iOS8

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

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

}