J'ai une UIButton
que j'ajoute à la vue de mon contrôleur de vue dans un storyboard. J'ajoute des contraintes de centrage pour le positionner et des contraintes d'espace pour limiter sa largeur. Dans le code j'ajoute:
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];
Le résultat est présenté ci-dessous:
Je veux que le bouton s'adapte à son contenu. Comment puis-je faire ceci?
J'ai essayé
[self.button sizeToFit];
et j'ai essayé de définir les priorités de contrainte de blocage automatique du contenu et de résistance à la compression.
J'ai également essayé de définir explicitement les variables contentEdgeInsets
et titleEdgeInsets
sur UIEdgeInsetsZero
et d'appeler invalidateIntrinsicContentSize
.
J'ai également remarqué que si je place des caractères de nouvelle ligne dans la chaîne de titre, le bouton semble redimensionner pour s'adapter à son contenu.
J'utilise Xcode 6 et iOS 8 sur le simulateur iPhone 6.
Cela fonctionne, mais vous devez utiliser un bouton personnalisé, pas un type de système. Attribuez au bouton des contraintes de largeur et de hauteur et créez un objet IBOutlet pour la contrainte de hauteur (heightCon dans mon code) afin de pouvoir l'ajuster dans le code.
- (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;
}
Après édition:
J'ai trouvé que vous pouvez aussi le faire plus simplement et avec un bouton système si vous créez une sous-classe et utilisez ce code,
@implementation RDButton
-(CGSize)intrinsicContentSize {
return CGSizeMake(self.frame.size.width, self.titleLabel.frame.size.height);
}
La méthode intrinsicContentSize substituée est appelée lorsque vous définissez le titre. Vous ne devez pas définir de contrainte de hauteur dans ce cas.
Swift 4.x version de Kubba's answer:
Besoin de mettre à jour Line Break sous la forme Clip/WordWrap/ dans le générateur Interface avec les boutons correspondants.
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
}
}
J'ai le même problème. Cela se produit uniquement si UIButton
's titleLabel
a plusieurs lignes. Est-ce un bug dans UIKit?
Ma solution Swift:
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
}
}
J'ai eu du mal avec cela pendant un moment et j'ai fini par le faire fonctionner en sous-classant UIButton et en ajoutant ces deux fonctions
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
}
}
Je suis loin de mon ordinateur et je ne peux donc pas ajouter le code pour l'instant, mais j'ai déjà trouvé une solution de contournement.
Ce que vous pouvez faire est de créer une UILabel
et d’ajouter une UITapGestureRecognizer
à l’étiquette. Faites ce que vous voulez pour l'action du bouton en gérant l'événement tap. Et assurez-vous également que vous activez les interactions utilisateur sur la UILabel
.
Cette étiquette se comportera désormais comme un bouton de redimensionnement automatique.
J'ai eu le même problème avec UIButton
avec un texte multiligne, et il avait aussi une image. J'ai utilisé sizeThatFits:
pour calculer la taille mais la mauvaise hauteur a été calculée.
Je ne l'ai pas fait UIButtonTypeCustom
, au lieu de cela j'ai appelé sizeThatFits:
sur le bouton titleLabel
avec une taille avec une largeur plus petite (à cause de l'image dans le bouton):
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;
Et puis j'ai utilisé la hauteur à partir de cette taille pour définir correctement le cadre du bouton, et cela a FONCTIONNÉ :)
Ils ont peut-être un problème avec le dimensionnement interne de UIButton
.
[self.button sizeToFit] devrait fonctionner si votre autolayout est désactivé. Si vous devez utiliser l'autolayout, d'autres suggestions (calcul de la largeur de ligne), etc.
Ce que je suggère est de calculer la largeur du texte et de calculer le cadre par vous-même. Ce n'est pas compliqué quand même, commencez par la largeur du texte:
[NSString sizeWithFont:font];
Effectuez une opération de modification et vous découvrirez facilement le nombre de lignes du texte.
Notez que cette méthode concerne les versions antérieures à iOS7, iOS 7 et après que vous souhaitiez peut-être essayer.
[NSString sizeWithAttributes:aDictionary];
Je devais invalider la taille du contenu intrinsèque lorsque les vues étaient affichées, puis calculer la hauteur du bouton pour la propriété intrinsicContentSize.
Voici le code dans 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)
}
Remplacez le - (CGSize) intrinsicContentSize dans UIButton personnalisé comme indiqué ci-dessous.
Objectif 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
}
}