2014-05-24 16 views
22

ho creato un controller della vista che assomiglia a questo:multilinea UIButton e AutoLayout

enter image description here

Voglio che i due top pulsanti di avere sempre 20 punti tra loro e la sinistra/bordi destro di tutta la vista . Dovrebbero sempre avere la stessa larghezza. Ho creato i vincoli per tutto questo e funziona esattamente come voglio. Il problema sono i vincoli verticali. I pulsanti dovrebbero sempre essere 20 punti sotto il bordo superiore. Dovrebbero avere la stessa altezza. Tuttavia, AutoLayout non rispetta che l'etichetta sinistra ha bisogno di due linee per adattarsi a tutti i suoi testi, quindi il risultato è simile al seguente:

enter image description here

voglio farlo sembrare come nella prima immagine. Non posso aggiungere vincoli di altezza costanti ai pulsanti perché quando l'app viene eseguita su iPad, è necessaria solo una linea e sarebbe quindi inutile avere uno spazio aggiuntivo.

In viewDidLoad ho provato questo:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    self.leftButton.titleLabel.preferredMaxLayoutWidth = (self.view.frame.size.width - 20.0 * 3)/2.0; 
    self.rightButton.titleLabel.preferredMaxLayoutWidth = (self.view.frame.size.width - 20.0 * 3)/2.0; 
} 

Ma questo non cambiava anyhting affatto.

La domanda: come faccio a rispettare l'autolayout se il pulsante sinistro richiede due righe?

+0

potrebbe sii perché hai il vincolo "stessa altezza" sul tasto sinistro. Questo renderà la stessa altezza degli altri pulsanti, cambiando la dimensione del contenuto all'interno del pulsante – user2277872

+0

Ho provato a rimuovere il vincolo "stessa altezza" ma non ha funzionato. –

+0

Hai provato ad aggiungere> = vincoli alle etichette per stabilire un valore minimo? – jaggedcow

risposta

1

Hai provato a usare questo:

self.leftButton.titleLabel.textAlignment = NSTextAlignmentCenter; 
self.leftButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail; 
self.leftButton.titleLabel.numberOfLines = 0; 
26

Ho avuto lo stesso problema in cui volevo che il mio tasto di crescere insieme al suo titolo. Ho dovuto sublocare il UIButton e il suo intrinsicContentSize in modo che restituisca la dimensione intrinseca dell'etichetta.

- (CGSize)intrinsicContentSize 
{ 
    return self.titleLabel.intrinsicContentSize; 
} 

Dal momento che l'UILabel è multilinea, la sua intrinsicContentSize è sconosciuto e si deve impostare il suo preferredMaxLayoutWidthSee objc.io article about that

- (void)layoutSubviews 
{ 
    [super layoutSubviews]; 
    self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.frame.size.width; 
    [super layoutSubviews]; 
} 

Il resto del layout dovrebbe funzionare. Se si imposta che entrambi i pulsanti hanno altezze uguali, l'altro crescerà. Il pulsante completo assomiglia a questo

@implementation TAButton 

- (instancetype)initWithCoder:(NSCoder *)coder 
{ 
    self = [super initWithCoder:coder]; 
    if (self) { 
     self.titleLabel.numberOfLines = 0; 
     self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; 
    } 
    return self; 
} 

- (CGSize)intrinsicContentSize 
{ 
    return self.titleLabel.intrinsicContentSize; 
} 

- (void)layoutSubviews 
{ 
    [super layoutSubviews]; 
    self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.frame.size.width; 
    [super layoutSubviews]; 
} 

@end 
+0

Ha funzionato perfettamente per me, grazie! Non avevo bisogno di impostare 'numberOfLines' e chiamare la seconda chiamata' [super layoutSubviews] '. – DMan

+2

VOGLIO BACIARE !!! SONO STATO FERMATO QUESTO MOLTO TEMPO !! – Yitzchak

+0

Davvero geniale. – matt

8

Swift versione in base alla risposta @Jan.

import UIKit 

class MultiLineButton: UIButton { 

    // MARK: - Init 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     self.commonInit() 
    } 

    private func commonInit() { 
     self.titleLabel?.numberOfLines = 0 
     self.titleLabel?.lineBreakMode = .ByWordWrapping 
    } 

    // MARK: - Overrides 

    override func intrinsicContentSize() -> CGSize { 
     return titleLabel?.intrinsicContentSize() ?? CGSizeZero 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     titleLabel?.preferredMaxLayoutWidth = titleLabel?.frame.size.width ?? 0 
     super.layoutSubviews() 
    } 

} 
1

AGGIORNATO Swift/Swift 2.0 versione sempre sulla base @ risposta di Jan

@IBDesignable 
class MultiLineButton:UIButton { 

    //MARK: - 
    //MARK: Setup 
    func setup() { 
    self.titleLabel?.numberOfLines = 0 

    //The next two lines are essential in making sure autolayout sizes us correctly 
    self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, forAxis: .Vertical) 
    self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, forAxis: .Horizontal) 
    } 

    //MARK:- 
    //MARK: Method overrides 
    required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    setup() 
    } 

    override init(frame: CGRect) { 
    super.init(frame: frame) 
    setup() 
    } 

    override func intrinsicContentSize() -> CGSize { 
    return self.titleLabel!.intrinsicContentSize() 
    } 

    override func layoutSubviews() { 
    super.layoutSubviews() 
    titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width 
    } 
} 
1

tweaks per Swift 3.1

intrisicContentSize è una struttura invece di una funzione di

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

classe completa in Swift 3 - sulla base di @Jan, @Quantaliinuxite e @ Matt bezark:

@IBDesignable 
class MultiLineButton:UIButton { 

    //MARK: - 
    //MARK: Setup 
    func setup() { 
     self.titleLabel?.numberOfLines = 0 

     //The next two lines are essential in making sure autolayout sizes us correctly 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, for: .vertical) 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, for: .horizontal) 
    } 

    //MARK:- 
    //MARK: Method overrides 
    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     setup() 
    } 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     setup() 
    } 

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

    override func layoutSubviews() { 
     super.layoutSubviews() 
     titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width 
    } 
} 
0

@ risposta di Jan doesn' lavoro per me in (almeno) iOS 8.1, 9.0 con Xcode 9.1. Il problema: -intrinsicContentSize restituisce una larghezza molto grande e un'altezza ridotta in quanto non vi è alcun limite di larghezza (titleLabel.frame in caso di chiamata ha una dimensione zero che porta al problema delle misurazioni). Inoltre, non tiene conto di possibili inserimenti e/o immagini.

Quindi, ecco la mia implementazione che dovrebbe risolvere tutte le cose (un solo metodo è davvero necessario):

@implementation PRButton 

- (CGSize)intrinsicContentSize 
{ 
    CGRect titleFrameMax = UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(
     self.bounds, self.alignmentRectInsets), self.contentEdgeInsets), self.titleEdgeInsets 
    ); 
    CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(titleFrameMax.size.width, CGFLOAT_MAX)]; 

    CGSize superSize = [super intrinsicContentSize]; 
    return CGSizeMake(
     titleSize.width + (self.bounds.size.width - titleFrameMax.size.width), 
     MAX(superSize.height, titleSize.height + (self.bounds.size.height - titleFrameMax.size.height)) 
    ); 
} 

@end 
+0

Questo non funziona per me, mentre la soluzione di Jan lo fa. –

2

Questo rispetta contenuti inserti bordo e ha lavorato per me:

class MultilineButton: UIButton { 

    func setup() { 
     self.titleLabel?.numberOfLines = 0 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow + 1, for: .vertical) 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow + 1, for: .horizontal) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     setup() 
    } 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     setup() 
    } 

    override var intrinsicContentSize: CGSize { 
     let size = self.titleLabel!.intrinsicContentSize 
     return CGSize(width: size.width + contentEdgeInsets.left + contentEdgeInsets.right, height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom) 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width 
    } 
} 
Problemi correlati