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

UIButton, который изменяет размер, чтобы соответствовать его titleLabel

У меня есть UIButton, который я добавляю к представлению контроллера вида в раскадровке. Я добавляю ограничения центрирования, чтобы расположить его и удержать ограничения пространства, чтобы ограничить его ширину. В коде я добавляю:

self.button.titleLabel.numberOfLines = 0;
self.button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[self.button setTitle:@"A real real real real real real real real long long name." forState:UIControlStateNormal];
self.button.backgroundColor = [UIColor redColor];
self.button.titleLabel.backgroundColor = [UIColor blueColor];

Результат показан ниже:

enter image description here

Я хочу, чтобы кнопка меняла свой контент. Как я могу это сделать?

Я пробовал

[self.button sizeToFit];

и я попытался установить приоритеты ограничений автоопределения содержимого и ограничения на сжатие.

Я также попытался явно установить параметры contentEdgeInsets и titleEdgeInsets в UIEdgeInsetsZero и вызвать invalidateIntrinsicContentsize.

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

Я запускаю Xcode 6 и iOS 8 на симуляторе iphone 6.

4b9b3361

Ответ 1

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

- (void)viewDidLoad {
    [super viewDidLoad];
    self.button.titleLabel.numberOfLines = 0;
    self.button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
    [self.button setTitle:@"A real real real real real real real real long long name." forState:UIControlStateNormal];
    [self.button addTarget:self action:@selector(doStuff:) forControlEvents:UIControlEventTouchUpInside];
    self.button.backgroundColor = [UIColor redColor];
    self.button.titleLabel.backgroundColor = [UIColor blueColor];
    [self.button layoutIfNeeded]; // need this to update the button titleLabel size
    self.heightCon.constant = self.button.titleLabel.frame.size.height;
}

После редактирования:

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

@implementation RDButton

-(CGSize)intrinsicContentSize {
    return CGSizeMake(self.frame.size.width, self.titleLabel.frame.size.height);
}

Вызывается переопределенный метод intrinsicContentSize при установке заголовка. В этом случае вы не должны устанавливать ограничение по высоте.

Ответ 2

Swift 3 версия ответ Кубба:

class ResizableButton: UIButton {
    override var intrinsicContentSize: CGSize {
       let labelSize = titleLabel?.sizeThatFits(CGSize(width: frame.width, height: .greatestFiniteMagnitude)) ?? .zero
       let desiredButtonSize = CGSize(width: labelSize.width + titleEdgeInsets.left + titleEdgeInsets.right, height: labelSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom)

       return desiredButtonSize
    }
}

Ответ 3

У вас такая же проблема. Это происходит, только если UIButton titleLabel имеет более одной строки. Это ошибка в UIKit?

My Swift:

class ResizableButton: UIButton {

override func intrinsicContentSize() -> CGSize
{
    let labelSize = titleLabel?.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max)) ?? CGSizeZero
    let desiredButtonSize = CGSizeMake(labelSize.width + titleEdgeInsets.left + titleEdgeInsets.right, labelSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom)

    return desiredButtonSize
}

Ответ 4

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

Что вы можете сделать, это создать UILabel и добавить UITapGestureRecognizer к метке. Сделайте все, что хотите для действия кнопки, обработав событие крана. А также убедитесь, что вы активируете взаимодействие пользователя с UILabel.

Теперь эта метка будет действовать как кнопка автоматического изменения размера.

Ответ 5

Я боролся с этим некоторое время и в конечном итоге сделал его работу путем подкласса UIButton и добавления этих двух функций

class GoalsButton: UIButton {

    override var intrinsicContentSize: CGSize {
        return self.titleLabel!.intrinsicContentSize
    }

    // Whever the button is changed or needs to layout subviews,
    override func layoutSubviews() {
        super.layoutSubviews()
        titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width
    }
}

Ответ 6

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

[NSString sizeWithFont:font];

Сделайте операцию mod, и вы легко узнаете количество строк для текста.

Обратите внимание, что этот метод предназначен для pre iOS7, для iOS 7 и после того, как вы захотите попробовать

[NSString sizeWithAttributes:aDictionary];

Ответ 7

[self.button sizeToFit] должен работать, если ваш автозапуск отключен. Если вам нужно использовать автозапуск, более подходящими являются другие предложения (расчет ширины линии) и т.д.

Ответ 8

У меня была такая же проблема с UIButton с многострочным текстом, и у него также было изображение. Я использовал sizeThatFits: для вычисления размера, но он рассчитал неправильную высоту.

Я не сделал это UIButtonTypeCustom, вместо этого я вызвал sizeThatFits: на кнопке titleLabel с размером с меньшей шириной (из-за изображения в кнопке):

CGSize buttonSize = [button sizeThatFits:CGSizeMake(maxWidth, maxHeight)];
CGSize labelSize = [button.titleLabel sizeThatFits:CGSizeMake(maxWidth - offset, maxHeight)]; // offset for image
buttonSize.height = labelSize.height;
buttonFrame.size = buttonSize;

И затем я использовал высоту от этого размера, чтобы правильно установить рамку кнопки, и она РАБОТАЛА:)

Возможно, у них есть ошибка во внутреннем размере UIButton.

Ответ 9

Переопределить intrinsicContentSize - (CGSize) в пользовательской UIButton, как указано ниже.

Цель - C:

-(CGSize)intrinsicContentSize {
    CGSize titleLabelIntrinsicSize = [self.titleLabel intrinsicContentSize];
    return CGSizeMake(titleLabelIntrinsicSize.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right, titleLabelIntrinsicSize.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom);
}

Swfit:

override var intrinsicContentSize: CGSize {
        get {
            if let thisSize = self.titleLabel?.intrinsicContentSize {
                return CGSize(width: thisSize.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right, height: thisSize.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom)
            }
            return super.intrinsicContentSize
        }
    }

Ответ 10

class SFResizableButton: UIButton {
  override var intrinsicContentSize: CGSize {
    get {
      var labelSize = CGSize.zero
        if let text = titleLabel?.text, let font = titleLabel?.font {
          labelSize.width = text.width(constrained: .greatestFiniteMagnitude, font: font)
        } else if let att = titleLabel?.attributedText {
          labelSize.width = att.width(constrained: .greatestFiniteMagnitude)
        }
      if let imageView = imageView {
        labelSize.width = labelSize.width + imageView.frame.width
      }
      let desiredButtonSize = CGSize(width: ceil(labelSize.width) + titleEdgeInsets.left + titleEdgeInsets.right + imageEdgeInsets.left + imageEdgeInsets.right, height: labelSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom + imageEdgeInsets.top + imageEdgeInsets.bottom)

        return desiredButtonSize
    }
  }
}
extesion String {
  func width(constrained height: CGFloat, font: UIFont) -> CGFloat {
    let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
      let boundingBox = (self as NSString).boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

      return boundingBox.width
  }
}

extension NSAttributedString {
  func width(constrained height: CGFloat) -> CGFloat {
    let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
      let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil)

      return boundingBox.width
  }
}