Горизонтальное выравнивание кнопок в представлении с использованием автомакета программно

Я пытаюсь выровнять две-три кнопки по горизонтали в представлении. Для простоты я покажу свою попытку выравнивания двух кнопок.

Это работает для кнопок с коротким заголовком:

@"H:|-10-[questionButton1(questionButton2)]-5-[questionButton2]-10-|"

введите здесь описание изображения

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

В итоге я вычислил ширину каждой кнопки, а затем, если ширина кнопки 1 больше половины представления и больше ширины кнопки 2, я использовал:

@"H:|-10-[questionButton1(==btn1width)]-5-[questionButton2(>=btn2width)]-10-|"

Это работает, но мне не очень нравится внешний вид моего кода с такими вычислениями. Только представьте сложность, которую добавляет третья кнопка. Кроме того, есть проблема, если обе кнопки имеют довольно длинный заголовок, и в этом случае мне придется выяснить, следует ли мне уменьшить размер шрифта, чтобы все уместилось.

Я публикую это здесь, потому что я мог упустить какую-то магическую вещь, касающуюся автомакета, поскольку я только сегодня начал использовать его в коде. Любая помощь будет принята с благодарностью.

--- ОБНОВЛЕНИЕ (уточнение) ---

Я хочу, чтобы кнопки разделялись равномерно с учетом полей (10 снаружи и 5 между кнопками). В идеале они должны быть одинаковой ширины, если размер текста соответствует размеру по умолчанию (50%:50% для двух кнопок и 33%:33%:33% для трех кнопок). В случае, если заголовок кнопки превышает эту идеальную ширину, кнопка должна увеличить свою ширину, если это разрешено другими кнопками (если другие могут сжиматься). Если расширение или сжатие невозможно, большая кнопка должна уменьшить размер шрифта и повторить процедуру (проверьте, могут ли другие кнопки сжиматься). Да, я знаю, я много прошу :)

как это выглядит, когда работает

--- ОБНОВИТЬ ---

Ответ @Sikhapol помог мне решить эту проблему. Я добавил несколько вещей, чтобы уменьшить размер шрифта, добавить отступы и сделать так, чтобы заголовки кнопок располагались в несколько строк, если текст не помещается:

btn.contentEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5);
btn.titleLabel.adjustsFontSizeToFitWidth = YES;
btn.titleLabel.numberOfLines = 0;
btn.titleLabel.minimumScaleFactor = 0.7;

Конечный результат: конечный результат


person budiDino    schedule 21.11.2014    source источник
comment
Непонятно, как должны выглядеть ваши кнопки. Вы хотите, чтобы каждый из них имел достаточную ширину для отображения своего заголовка, но при этом расширялся до ширины представления (минус отступы 10-5-10)? Вы хотите, чтобы они оба имели одинаковую ширину, но при необходимости уменьшали размер шрифта (я почти уверен, что нет простого способа сделать это без вычисления размеров заголовков)?   -  person rdelmar    schedule 21.11.2014


Ответы (3)


Используйте Приоритет устойчивости к сжатию контента!

Вы можете настроить автоматическую компоновку, чтобы она старалась поддерживать равную ширину двух меток, насколько это возможно. Но вы говорите ему, что более важно позволить одному из них стать больше, чтобы вместить содержимое внутри.

Для этого установите приоритет ограничения равной ширины ниже, чем приоритет сопротивления сжатию содержимого меток (или кнопок).

- (void)viewDidLoad {
    [super viewDidLoad];

    UILabel *label1 = [[UILabel alloc] init];
    label1.text = @"this seems";
    label1.backgroundColor = [UIColor orangeColor];
    label1.translatesAutoresizingMaskIntoConstraints = NO;

    UILabel *label2 = [[UILabel alloc] init];
    label2.text = @"completely fine";
    label2.backgroundColor = [UIColor orangeColor];
    label2.translatesAutoresizingMaskIntoConstraints = NO;

    [self.view addSubview:label1];
    [self.view addSubview:label2];

    NSDictionary *views = NSDictionaryOfVariableBindings(label1, label2);

    NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[label1(label2)]-5-[label2]-10-|"
                                                                             options:NSLayoutFormatAlignAllCenterY
                                                                             metrics:nil
                                                                               views:views];

    // Find the equal width constraint and set priority to high (750)
    for (NSLayoutConstraint *constraint in horizontalConstraints) {
        if (constraint.firstAttribute == NSLayoutAttributeWidth) {
            constraint.priority = UILayoutPriorityDefaultHigh;
        }
    }

    [self.view addConstraints:horizontalConstraints];

    // Set content compression resistant to required (1000)
    [label1 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    [label2 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];

    // The below code is here to add the vertical center constraints. You can ignore it.
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1
                                                          attribute:NSLayoutAttributeCenterY
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterY
                                                         multiplier:1
                                                           constant:0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2
                                                          attribute:NSLayoutAttributeCenterY
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterY
                                                         multiplier:1
                                                           constant:0]];
}

Итак, если содержимое может поместиться внутри этих меток:

подходит

Но если один из них вырастет длиннее:

развернуть

Приоритет сопротивления сжатию содержимого — это способ сообщить автоматической компоновке, насколько далеко вы хотите, чтобы компонент сохранял свой собственный размер (отсюда и название сопротивления сжатию).

Этот подход также легче реализовать в IB. Приоритет сопротивления содержимого можно установить на вкладке Инспектор размеров (cmd + opt + 5).

person yusuke024    schedule 21.11.2014
comment
Спасибо, добавление этих частей с приоритетом улучшило все;) Я также добавил несколько вещей, чтобы мои кнопки уменьшали размер шрифта, а их заголовок при необходимости занимал несколько строк. btn.contentEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5); btn.titleLabel.adjustsFontSizeToFitWidth = YES; btn.titleLabel.numberOfLines = 0; btn.titleLabel.minimumScaleFactor = 0,7; - person budiDino; 21.11.2014

Если вы используете Auto Layout, вы можете просто использовать ограничение, чтобы ваши кнопки всегда были выровнены по вертикали или по горизонтали. Чтобы выровнять их по горизонтали (т.е. выровнять их значения по оси y, чтобы они были одинаковыми), просто выберите две кнопки, удерживая команду и щелкая по ним по отдельности: введите здесь описание изображения

Они появятся в раскадровке с индикаторами выбора вокруг них. Теперь перейдите в правый нижний угол и выберите выравнивание их «вертикальных центров». Выравнивание их вертикальных центров выровняет их по горизонтали (на основе вашей схемы).

введите здесь описание изображения

Это гарантирует, что они всегда будут выровнены по горизонтали.

Чтобы решить вашу проблему с расширением текста, я могу придумать один способ обойти это: создать UIView, а затем поместить внутрь UILabel для имитации кнопки. Вам нужно будет связать представление с некоторым IBOutlet, чтобы получить его при нажатии, и связать его с функцией, которую вы хотите, чтобы он выполнял. Но у UILabel есть атрибуты, которые вы можете установить в раскадровке, показанной здесь, с помощью инспектора атрибутов:

введите здесь описание изображения

Если вы выберете «Минимальный размер шрифта», установите это значение, тогда ваш текст будет автоматически уменьшаться, поскольку он заполняет выделенное пространство, как показано здесь:

введите здесь описание изображениявведите здесь описание изображения

person eager to learn    schedule 21.11.2014

По мере того, как текст увеличивается, чтобы заполнить свою ширину, вы получаете неоднозначность ограничения. Неизвестно, что произойдет! Вам нужно использовать приоритеты ограничений и неравенства (и, возможно, измененное сопротивление сжатию), чтобы решить эту проблему.

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

    let p = self.lab2.contentCompressionResistancePriorityForAxis(.Horizontal)
    self.lab1.setContentCompressionResistancePriority(p+1, forAxis: .Horizontal)

Но мне также нужно было использовать неравенства для первоначальной установки ширины и интервала:

    self.view.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "H:[v1(>=20)]-(>=20)-[v2(>=20)]", options: nil, metrics: nil, views: d)
    )
person matt    schedule 21.11.2014
comment
Лучше всего загрузить исходный проект и запустить его, который находится здесь: github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ Это небольшая лаборатория того, что происходит, когда объекты становятся шире из-за удлинения текста и других вещи нужно сказать, как уступить. - person matt; 21.11.2014