it-swarm.com.ru

Autolayout - внутренний размер UIButton не включает титульные вставки

Если у меня UIButton организован с использованием autolayout, его размер корректно подстраивается под его содержимое.

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

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

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

enter image description here

Правка:

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

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

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

156
Ben Packard

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

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

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

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

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

  • Если вы установите отрицательную левую вставку изображения, фактический макет использует половину этого значения. Таким образом, чтобы получить левую вставку -20, вы должны использовать левую вставку -40 в Interface 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)
151
jaredsinclair

Вы можете заставить это работать в Интерфейсном Разработчике (без написания какого-либо кода), используя комбинацию отрицательных и положительных Заголовка и Вкладок Содержания. 

enter image description here

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

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

enter image description here

177
n.Drake

Почему бы не переопределить метод 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);
}

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

91
Maarten

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

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

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

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 точек заполнения между текстом и изображением.

18
Brian Gerstle

И для Свифта это сработало:

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)
    }
}

Любовь У Свифт

18
pegpeg

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

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)

    }

}
7
TheoK

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

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

 enter image description here

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

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

Я хотел добавить 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 связаны друг с другом, требует небольшого вознаграждения за каждую вставку. Поэтому, если вы добавляете несколько вставок слева от заголовка, вы должны добавить отрицательную вставку справа и предоставить больше места (через положительную вставку) справа от содержимого.

При добавлении правильной вставки содержимого в соответствии со смещением вставок заголовка мой текст не выходит за пределы кнопки.

3
orj

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

Interface builder screenshot

3
zeiteisen

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

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

Где 8, какой бы ни была ваша вставка.

1
Bob Spryn

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

 extension UIButton {

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