webentwicklung-frage-antwort-db.com.de

UIButton, dessen Größe an das titleLabel angepasst wird

Ich habe eine UIButton, die ich der Ansicht meines Ansichtscontrollers in einem Storyboard hinzufüge. Ich füge Zentrierungsbeschränkungen hinzu, um es zu positionieren, und führende Raumbeschränkungen, um seine Breite zu begrenzen. Im Code füge ich hinzu:

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];

Das Ergebnis wird unten gezeigt:

enter image description here

Ich möchte, dass sich die Schaltfläche an den Inhalt anpasst. Wie kann ich das machen?

Ich habe es versucht 

[self.button sizeToFit];

und ich habe versucht, die Prioritäten der Prioritäten für die Inhaltsanpassung und Komprimierungsbeständigkeit auf erforderlich zu setzen.

Ich habe auch versucht, contentEdgeInsets und titleEdgeInsets explizit auf UIEdgeInsetsZero zu setzen und invalidateIntrinsicContentSize aufzurufen. 

Ich habe auch bemerkt, dass, wenn ich Zeilenumbrüche in die Titelzeichenfolge setze, die Größe der Schaltfläche an den Inhalt angepasst wird.

Ich verwende Xcode 6 und iOS 8 auf dem iPhone 6 Simulator.

26
Darren

Ich habe das zum Laufen gebracht, aber Sie müssen eine benutzerdefinierte Schaltfläche verwenden, nicht einen Systemtyp. Geben Sie der Schaltfläche sowohl die Breiten- als auch die Höhenbeschränkungen an, und passen Sie ein IBOutlet an die Höhenbeschränkung an (heightCon in meinem Code), damit Sie es im Code anpassen können.

- (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's titleLabel's size
    self.heightCon.constant = self.button.titleLabel.frame.size.height;
}

Nach der Bearbeitung:

Ich habe festgestellt, dass Sie dies auch einfacher tun können, und mit einer Systemschaltfläche, wenn Sie eine Unterklasse erstellen und diesen Code verwenden,

@implementation RDButton

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

Die überschriebene intrinsicContentSize-Methode wird aufgerufen, wenn Sie den Titel festlegen. Sie sollten in diesem Fall keine Höhenbeschränkung festlegen.

18
rdelmar

Swift 4.x version von Kubbas answer:

Sie müssen Zeilenumbruch als Clip/WordWrap/ im Interface-Builder mit entsprechenden Schaltflächen aktualisieren.

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
    }
}
20
A. Buksha

Habe das gleiche Problem. Dies passiert nur, wenn UIButton 's titleLabel mehr als eine Zeile hat. Ist es ein Fehler in UIKit?

Meine Swift Lösung:

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

        return desiredButtonSize
    }
}
14
Kubba

Ich hatte einige Zeit damit zu kämpfen und endete damit, dass ich UIButton als Unterklassen einsetzte und diese beiden Funktionen hinzufügte

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
    }
}
3
Lord Fresh

Ich bin nicht an meinem Computer und kann den Code jetzt nicht hinzufügen, aber ich habe bereits eine Problemumgehung gefunden. 

Sie können eine UILabel erstellen und dem Label eine UITapGestureRecognizer hinzufügen. Machen Sie das, was Sie für die Aktion der Schaltfläche tun möchten, indem Sie das Tap-Ereignis behandeln. Stellen Sie außerdem sicher, dass Sie Benutzerinteraktionen für die Variable UILabel aktivieren.

Dieses Label verhält sich jetzt wie eine Schaltfläche zum automatischen Ändern der Größe.

2
Vinay Jain

Ich hatte das gleiche Problem mit UIButton mit mehrzeiligem Text und hatte auch ein Bild. Ich habe sizeThatFits: verwendet, um die Größe zu berechnen, aber es wurde eine falsche Höhe berechnet.

Ich habe es nicht UIButtonTypeCustom gemacht, stattdessen habe ich sizeThatFits: auf der titleLabel der Schaltfläche mit der kleineren Breite (aufgrund des Bildes in der Schaltfläche) aufgerufen:

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;

Und dann habe ich aus dieser Größe die Höhe verwendet, um den Rahmen der Schaltfläche richtig einzustellen, und es funktionierte :)

Vielleicht haben sie einen Fehler in der internen Größenänderung von UIButton.

1
BSevo

[self.button sizeToFit] sollte funktionieren, wenn Ihr Autolayout deaktiviert ist. Wenn Sie Autolayout verwenden müssen, sind andere Vorschläge (Berechnen der Linienbreite) usw. geeigneter.

1
Aamir

Ich würde vorschlagen, die Breite des Textes und den Rahmen selbst zu berechnen. Es ist sowieso nicht kompliziert, man muss zuerst die Breite des Textes ermitteln:

[NSString sizeWithFont:font];

Machen Sie eine Mod-Operation und Sie werden leicht die Anzahl der Zeilen für den Text herausfinden.

Beachten Sie, dass diese Methode für iOS 7 vor iOS 7 und danach gilt

[NSString sizeWithAttributes:aDictionary];
1
Xiangdong
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
  }
}
0
looseyi

Ich musste die intrinsische Inhaltsgröße ungültig machen, als die Ansichten angeordnet wurden, und dann die Höhe der Schaltfläche für die intrinsicContentSize-Eigenschaft berechnen. 

Hier ist der Code in Swift3/Xcode 9

override func layoutSubviews() {
    self.invalidateIntrinsicContentSize()
    super.layoutSubviews()
}


override var intrinsicContentSize: CGSize {
    return CGSize(width: self.frame.size.width, height: titleLabel!.frame.size.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
0
Maria

Überschreiben Sie - (CGSize) intrinsicContentSize in Custom UIButton wie unten angegeben.

Ziel 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
        }
    }
0
Bhavesh Patel