Autolayout - собственный размер UIButton не включает в себя вставки заголовков

Если у меня есть UIButton, организованный с использованием автозапуска, его размер прекрасно настраивается, чтобы соответствовать его контенту.

Если я установил изображение как button.image, размер экземпляра снова, похоже, учитывает это.

Однако, если я настраиваю кнопку titleEdgeInsets кнопки, макет не учитывает это и вместо этого сокращает заголовок кнопки.

Как я могу гарантировать, что внутренняя ширина кнопки учитывает вставку?

enter image description here

Edit:

Я использую следующее:

[self.backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];

Цель состоит в том, чтобы добавить некоторое разделение между изображением и текстом.

Ответ 1

Вы можете решить эту проблему без необходимости переопределять любые методы или устанавливать произвольное ограничение ширины. Вы можете сделать все это в Interface Builder следующим образом.

  • Внутренняя ширина кнопки получается из ширины заголовка плюс ширина значка плюс вставки левого и правого содержимого.

  • Если кнопка имеет как изображение, так и текст, они центрируются как группа, без пробелов между ними.

  • Если вы добавите левую вставку содержимого, ее вычислено относительно текста, а не значок "текст +".

  • Если вы устанавливаете вставку с отрицательным левым изображением, изображение вытягивается влево, но общая ширина кнопки не изменяется.

  • Если вы устанавливаете вставку с отрицательным левым изображением, фактический макет использует половину этого значения. Таким образом, чтобы получить вставку -20 точек влево, вы должны использовать значение вставки -40 точек в интерфейсе Builder.

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

Некоторые примерные значения:

// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)

Ответ 2

Вы можете заставить это работать в Interface Builder (без написания кода), используя комбинацию отрицательных и позитивных вложений Title и Content.

enter image description here

Обновить. В Xcode 7 есть ошибка, в которой вы не можете вводить отрицательные значения в поле Right Inset, но вы можете использовать шаговый элемент управления рядом с ним для уменьшения значения. (Спасибо Stuart)

Выполняя это, вы добавите 8pt интервала между изображением и заголовком и увеличите внутреннюю ширину кнопки на ту же сумму. Вот так:

enter image description here

Ответ 3

Почему бы не переопределить метод intrinsicContentSize в UIView? Например:

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    return CGSizeMake(s.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right,
                      s.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}

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

Ответ 4

Вы не указали, как вы устанавливаете вставки, поэтому я предполагаю, что вы используете titleEdgeInsets, потому что я вижу тот же эффект, который вы получаете. Если я использую contentEdgeInsets, он работает правильно.

- (IBAction)ChangeTitle:(UIButton *)sender {
    self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
    [self.button setTitle:@"Long Long Title" forState:UIControlStateNormal];
}

Ответ 5

И для Swift это сработало:

extension UIButton {
    override open var intrinsicContentSize: CGSize {
        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)
    }
}

Любовь U Swift

Ответ 6

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

UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
                                            -desiredRightPadding,
                                            -desiredTopPadding,
                                            -desiredLeftPadding);

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

Button with image and short text

Button with image and long text

Вы можете видеть, что фактический кадр кнопки не охватывает метку (поскольку метка смещена на 10 пунктов вправо, за пределы границ), но мы достигли 10 точек заполнения между текстом и изображением.

Ответ 7

Для Swift 3 на основе pegpeg answer:

extension UIButton {

    override open var intrinsicContentSize: CGSize {

        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)

    }

}

Ответ 8

Все выше не работало для iOS 9 +, что я сделал:

  • Добавьте ограничение ширины (для минимальной ширины, когда кнопка не имеет текста. Кнопка будет автоматически масштабироваться, если текст предоставлен)
  • установить отношение к значению большего или равного

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

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

button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);

Ответ 9

Я хотел добавить 5pt пробел между моей иконкой UIButton и ярлыком. Так я достиг этого:

UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// more button config etc
infoButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5);
infoButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5);

Способ, которым contentEdgeInsets, titleEdgeInsets и imageEdgeInsets соотносятся друг с другом, требует немного отдачи и принятия от каждой вставки. Поэтому, если вы добавите некоторые вставки в заголовок слева, вам нужно добавить отрицательную вставку справа и предоставить еще немного места (через положительную вставку) в правом правиле.

Добавив нужную вставку содержимого для соответствия сдвигу заглавных букв, мой текст не выходит за рамки кнопки.

Ответ 10

Опция также доступна в построителе интерфейса. См. Вставку. Я устанавливаю слева и справа на 3. Работает как шарм.

Interface builder screenshot

Ответ 11

Решение, которое я использую, заключается в добавлении ограничения ширины на кнопку. Затем, где-то в инициализации, после того, как ваш текст установлен, обновите ограничение ширины следующим образом:

self.buttonWidthConstraint.constant = self.shareButton.intrinsicContentSize.width + 8;

Где 8 - какая бы ни была ваша вставка.

Ответ 12

Вызов sizeToFit() гарантирует, что contentEdgeInset вступит в силу

extension UIButton {

   open override func draw(_ rect: CGRect) { 
       self.contentEdgeInsets = UIEdgeInsets(top: 10, left: 40, bottom: 10, right: 40)
       self.sizeToFit()
   }
}