iOS: розмір UIButton змінюється відповідно до довжини тексту


134

У програмі інтерфейсу, утримуючи Command+, =змінить розмір кнопки відповідно до її тексту. Мені було цікаво, чи можна це зробити програмно перед тим, як кнопка була додана до перегляду.

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button.titleLabel setFont:[UIFont fontWithName:@"Arial-BoldMT" size:12]];
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
// I need to know the width needed to accomodate NSStringVariable
[button setTitle:NSStringVariable forState:UIControlStateNormal]; 
// So that I can set the width property of the button before addSubview
[button setFrame:CGRectMake(10, 0, width, fixedHeight)];
[subNavigation addSubview:button];

1
Зверніть увагу на це дуже давнє запитання: сьогодні (2017) просто встановіть обмеження як "більше або рівне", і воно все робить. (Зауважте відповідь нижче від Tad.)
Fattie

@Fattie Обмеження " більшого або рівного " недостатньо для сумісності з AutoLayout. У наш час (2017+) слід або загорнути кнопку всередину щось, що відповідає правильному розміру (відповідь Bartłomiej Semańczyk), або підкласифікувати UIButton, як у stackoverflow.com/a/50575588/1033581
Cœur

Привіт @ Cœur - існує багато тонкощів для автоматичного розкладу. Можливо, ви думаєте про дещо іншу ситуацію? Однак, на щастя, ви абсолютно помиляєтесь - просто спробуйте !! Просто поставте UIButton на контролер перегляду. очевидно встановити горизонтальний і вертикальний центр. А потім додайте обмеження ширини> = 100. він чудово працює в останніх iOS.
Fattie

1
(Для всіх, хто тут не працює з автоматичним розгортанням Google ........... просто TBC вам взагалі нічого не потрібно додавати, і UIButton (також UILabel тощо) автоматично змінить розмір до ширини із змінами тексту. Просто обмеження належним чином позиції H / V.)
Fattie

@Fattie демонстрація . Зокрема, під час виконання роботи він поводиться так: github.com/Coeur/autolayoutButton/blob/master/buttonSelfSizing/…
Cœur

Відповіді:


1

У Xcode 4.5 і вище це тепер можна зробити за допомогою " Автоматичного компонування / обмежень ".

Основними перевагами є те, що:

  1. Вам зовсім не потрібно програмно встановлювати кадри!
  2. Якщо все зроблено правильно, вам не потрібно займатись скиданням кадрів для зміни орієнтації.
  3. Також зміни пристрою не повинні вас турбувати (читайте, не потрібно кодувати окремо для різних розмірів екрана).

Кілька недоліків:

  1. Не сумісний із зворотним ходом - працює лише для iOS 6 і вище.
  2. Потрібно ознайомитися (але це заощадить час згодом).

Найкрутіше, що ми повинні зосередитись на декларуванні наміру, такого як:

  • Я хочу, щоб ці дві кнопки були однакової ширини; або
  • Мені потрібно, щоб цей погляд був вертикально центрований і поширювався на максимум 10 балів від краю нагляду; або навіть,
  • Я хочу, щоб ця кнопка / мітка змінила розмір відповідно до мітки, яку вона відображає!

Ось простий підручник для ознайомлення з автоматичним компонуванням.

Для більш детальної інформації .

Спочатку це потребує певного часу, але, звичайно, схоже, що це буде варте зусиль.


3
Я майже не пропустив цю відповідь - їй дійсно потрібно набагато більше голосів. Завдяки цьому рішенню можна уникнути вбудови шрифтових імен та розмірів або дзвінків лише для iOS 7 Я просто встановив обмеження сторони, на якій хотів, щоб мій UIButton продовжився, і все.
Карл

Майже ідеальне рішення, на жаль, воно не працює, якщо ви використовуєте titleEdgeInsets: /
Zoltán

130
Це погана відповідь - вона детально описує достоїнства самого AutoLayout, а не те, як AutoLayout можна застосувати в цій ситуації для вирішення проблеми запитувача.
матцвен

4
Мені було цікаво, чи можна це зробити програмно, говорить відповідь ...
Juan Boero

@JuanPabloBoeroAlvarez Обмеження автоматичного макета можуть бути визначені в Інструменті інтерфейсу та / або програмно.
Сліп Д. Томпсон

130

У UIKit є доповнення до класу NSString, щоб отримати від заданого об’єкта NSString розмір, який він буде приймати, коли він відображатиметься певним шрифтом.

Документи були тут . Тепер тут під Застарілі.

Якщо коротко, якщо ви йдете:

CGSize stringsize = [myString sizeWithFont:[UIFont systemFontOfSize:14]]; 
//or whatever font you're using
[button setFrame:CGRectMake(10,0,stringsize.width, stringsize.height)];

... ви встановите рамку кнопки на висоту та ширину рядка, який ви переказуєте.

Ви, ймовірно, захочете експериментувати з деяким буферним простором навколо цього CGSize, але ви будете починати в потрібному місці.


4
Схоже, прокладка iOS за замовчуванням - 12 пікселів, 8 пікселів.
Бен Лачман

19
розмірWithFont застарілий у iOS 7.0. Використовуйте sizeWithAttributes: замість цього
carmen_munich

6
Я настійно рекомендую більше не грати з кадрами, а ТІЛЬКИ з обмеженнями.
Гіль Санд

@GilSand Чи є спосіб використовувати для цього конструктор інтерфейсів?
huggie

Так, пошук у Google має дати вам багато корисних результатів
Gil Sand,

101

Спосіб зробити це в коді:

[button sizeToFit];

Якщо ви підкласифікуєте і хочете додати додаткові правила, ви можете перекрити:

- (CGSize)sizeThatFits:(CGSize)size;

5
sizeToFit прекрасно працює на стандартних елементах управління, таких як UIButton або UILabel. Якщо ви робите це на користувацькому UIView, вам потрібно буде реалізувати -(CGSize)sizeThatFits:(CGSize)size.
Камерон Лоуелл Палмер

4
Він працює, лише якщо ви поставите його після встановлення тексту, інакше недостатньо інформації про те, наскільки він повинен бути великим: [button setTitle:@"Your text here" forState:UIControlStateNormal]; [button sizeToFit]; Також якщо ви оновлюєте текст пізніше, не забудьте зателефонувати ще раз.
Хуан Боеро

Переконайтеся, що ви встановили текст лише таким чином: [myButton setTitle: @ "my title" forState: UIControlStateNormal]; Для мене це не спрацювало, поки я не повторив це твердження.
Дарій Міліаускас

7
sizeToFit()не поважає вставки заголовка.
келін

32

Якщо ваша кнопка створена за допомогою Інтерфейсу Builder, і ви змінюєте заголовок у коді, ви можете зробити це:

[self.button setTitle:@"Button Title" forState:UIControlStateNormal];
[self.button sizeToFit];

1
І ви можете до цього, навіть якщо ваша кнопка була зроблена з кодом.
Маркус

22

Швидкий:

Тут важливо, коли ви будете телефонувати .sizeToFit(), це має бути після встановлення тексту для відображення, щоб він міг прочитати потрібний розмір, якщо пізніше оновити текст, а потім зателефонувати ще раз.

var button = UIButton()
button.setTitle("Length of this text determines size", forState: UIControlState.Normal)
button.sizeToFit()
self.view.addSubview(button)

18

Щоб виконати це за допомогою авторозмітки, спробуйте встановити обмеження ширини змінної:

Обмеження ширини

Вам також може знадобитися скорегувати свої результати Content Hugging Priorityта Content Compression Resistance Priorityотримати необхідні результати.


UILabel повністю автоматично змінює розмір :

Цей UILabel просто встановлений по центру на екрані (лише два обмеження, горизонтальний / вертикальний):

Він змінює ширину повністю автоматично:

Не потрібно встановлювати будь-яку ширину чи висоту - це повністю автоматично.

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

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

Зауважте, маленькі жовті квадрати просто прикріплені ("проміжки" нуля). Вони автоматично переміщуються по мірі зміни розміру UILabel.

Додавання обмеження "> =" встановлює мінімальну ширину для UILabel:

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


16

Якщо ви хочете змінити розмір тексту на відміну від кнопки, ви можете використовувати ...

button.titleLabel.adjustsFontSizeToFitWidth = YES;
button.titleLabel.minimumScaleFactor = .5;
// The .5 value means that I will let it go down to half the original font size 
// before the texts gets truncated

// note, if using anything pre ios6, you would use I think
button.titleLabel.minimumFontSize = 8;

3
* коригуєFontSizeToFitWidth
Daniel Bang

8

sizeToFit працює неправильно. натомість:

myButton.size = myButton.sizeThatFits(CGSize.zero)

ви також можете додати contentInsetдо кнопки:

myButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 4, 8)


Від документів Apple щодо sizeToFit: // виклику sizeThatFits: з поточними межами перегляду та зміною розміру меж. Отже, це працює правильно, ви просто повинні встановити його після того, як ви встановите текст.
Маркус

5

Просто:

  1. Створіть UIView як обгортку з автоматичним макетом для перегляду навколо.
  2. Покладіть UILabelвсередину цієї обгортки. Додайте обмеження, які будуть наклеювати ваш ярлик на краї обгортки.
  3. Покладіть UIButtonвсередину обгортки, а потім просто додайте ті самі обмеження, що і ви UILabel.
  4. Насолоджуйтесь кнопкою автоматичного набору разом з текстом.

1
Чи добре це грає з доступністю?
jasonszhao

4

Швидкий 4.2

Слава богу, це вирішило. Встановивши текст на кнопку, ви можете отримати IntrinsicContentSize, який має натуральний розмір, з UIView (офіційний документ тут ). Для UIButton ви можете використовувати його як нижче.

button.intrinsicContentSize.width

Для вашої інформації я відкоригував ширину, щоб вона виглядала належним чином.

button.frame = CGRect(fx: xOffset, y: 0.0, width: button.intrinsicContentSize.width + 18, height: 40)

Симулятор

Кнопки UIB з intrinsicContentSize

Джерело: https://riptutorial.com/ios/example/16418/get-uibutton-s-size-strictly-based-on-its-text-and-font


1
Не могли б ви дати трохи більше контексту? Як ваш рядок коду стосується коду у питанні? Чи можете ви також підсумувати те, що робить запропонований вами код? Надання посилання як пояснення не є правильним форматом для цього сайту (див. Мета.stackexchange.com/a/8259/266197 з причин), але якщо ви додасте пояснення та контекст, ваша відповідь стане більш цінною!
NOhs

3

У мене є додаткові потреби, пов’язані з цією посадою, які sizeToFitне вирішують. Мені потрібно було тримати кнопку по центру в оригінальному місці, незалежно від тексту. Я також ніколи не хочу, щоб кнопка була більшою за її початковий розмір.

Отже, я розміщую кнопку для її максимального розміру, зберігаю цей розмір у контролері та використовую наступний метод для розміру кнопки, коли текст змінюється:

+ (void) sizeButtonToText:(UIButton *)button availableSize:(CGSize)availableSize padding:(UIEdgeInsets)padding {    

     CGRect boundsForText = button.frame;

    // Measures string
    CGSize stringSize = [button.titleLabel.text sizeWithFont:button.titleLabel.font];
    stringSize.width = MIN(stringSize.width + padding.left + padding.right, availableSize.width);

    // Center's location of button
    boundsForText.origin.x += (boundsForText.size.width - stringSize.width) / 2;
    boundsForText.size.width = stringSize.width;
    [button setFrame:boundsForText];
 }

1

Цей клас кнопок з висотою автоматичного розміру тексту (для Xamarin, але може бути переписаний для іншої мови)

[Register(nameof(ResizableButton))]
public class ResizableButton : UIButton
{
    NSLayoutConstraint _heightConstraint;
    public bool NeedsUpdateHeightConstraint { get; private set; } = true;

    public ResizableButton(){}

    public ResizableButton(UIButtonType type) : base(type){}

    public ResizableButton(NSCoder coder) : base(coder){}

    public ResizableButton(CGRect frame) : base(frame){}

    protected ResizableButton(NSObjectFlag t) : base(t){}

    protected internal ResizableButton(IntPtr handle) : base(handle){}

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();
        UpdateHeightConstraint();
        InvalidateIntrinsicContentSize();
    }

    public override void SetTitle(string title, UIControlState forState)
    {
        NeedsUpdateHeightConstraint = true;
        base.SetTitle(title, forState);
    }

    private void UpdateHeightConstraint()
    {
        if (!NeedsUpdateHeightConstraint)
            return;
        NeedsUpdateHeightConstraint = false;
        var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));

        var rect = new CGRect(Frame.X, Frame.Y, Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);

        if (_heightConstraint != null)
            RemoveConstraint(_heightConstraint);

        _heightConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, rect.Height);
        AddConstraint(_heightConstraint);
    }

     public override CGSize IntrinsicContentSize
     {
         get
         {
             var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));
             return new CGSize(Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);
         }
     }
}

1

Чомусь func sizeToFit()для мене це не працює. Моя настройка полягає в тому, що я використовую кнопку всередині a UITableViewCellі використовую автоматичне розташування.

Що для мене працювало:

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

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

Ось два назви з Debug View Hierachry введіть тут опис зображення

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


0

Якщо чесно, я вважаю, що це справді соромно, що в розкладинці не існує простого прапорця, який би сказав, що ви хочете змінити розміри кнопок, щоб вмістити текст. Ну ... що завгодно.

Ось найпростіше рішення за допомогою раскадровки.

  1. Розмістіть UIView і поставте для нього обмеження. Приклад: введіть тут опис зображення
  2. Помістіть UILabel всередині UIView. Встановіть обмеження, щоб прикріпити його до країв UIView.

  3. Розмістіть свій UIButton в UIView. Встановіть ті ж обмеження, щоб прикріпити його до країв UIView.

  4. Встановіть 0 для кількості рядків UILabel. введіть тут опис зображення

  5. Налаштування торгових точок.

    @IBOutlet var button: UIButton!
    @IBOutlet var textOnTheButton: UILabel!
  1. Отримайте якусь довгу, довгу, довгу назву.

    let someTitle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
  1. На viewDidLoad встановити заголовок і для UILabel, і для UIButton.

    override func viewDidLoad() {
        super.viewDidLoad()
        textOnTheButton.text = someTitle
        button.setTitle(someTitle, for: .normal)
        button.titleLabel?.numberOfLines = 0
    }
  1. Запустіть її, щоб переконатися, що розмір кнопки змінено та його можна натиснути.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.