UIButton: come centrare un'immagine e un testo usando imageEdgeInsets e titleEdgeInsets?


159

Se inserisco solo un'immagine in un pulsante e imposto imageEdgeInsets più vicino all'inizio, l'immagine rimane centrata e tutto funziona come previsto:

[button setImage:image forState:UIControlStateNormal];
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, 0.0)];

Se inserisco solo un testo in un pulsante e imposto titleEdgeInsets più vicino al fondo, il testo rimane centrato e tutto funziona come previsto:

[button setTitle:title forState:UIControlStateNormal];
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, -30, 0.0)];

Ma, se unisco le 4 linee, il testo interferisce con l'immagine ed entrambi perdono l'allineamento centrale.

Tutte le mie immagini hanno una larghezza di 30 pixel e se inserisco 30 nel parametro sinistro di UIEdgeInsetMake per setTitleEdgeInsets, il testo viene nuovamente centrato. Il problema è che l'immagine non viene mai centrata perché sembra che dipenda dalla dimensione button.titleLabel. Ho già provato molti calcoli con dimensioni dei pulsanti, dimensioni dell'immagine, dimensioni dell'etichetta del titolo e mai entrambi perfettamente centrati.

Qualcuno ha già avuto lo stesso problema?

Risposte:


412

Per quello che vale, ecco una soluzione generale per posizionare l'immagine centrata sopra il testo senza usare numeri magici. Tieni presente che il codice seguente non è aggiornato e probabilmente dovresti utilizzare una delle versioni aggiornate di seguito :

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered 
//  below the image
CGSize imageSize = button.imageView.frame.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
  0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = button.titleLabel.frame.size;
button.imageEdgeInsets = UIEdgeInsetsMake(
  - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

La seguente versione contiene modifiche per supportare iOS 7+ che sono state consigliate nei commenti seguenti. Non ho testato questo codice da solo, quindi non sono sicuro di come funzioni o se si romperà se utilizzato nelle versioni precedenti di iOS.

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered 
//  below the image
CGSize imageSize = button.imageView.image.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
  0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}];
button.imageEdgeInsets = UIEdgeInsetsMake(
  - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

// increase the content height to avoid clipping
CGFloat edgeOffset = fabsf(titleSize.height - imageSize.height) / 2.0;
button.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0);

Versione Swift 5.0

extension UIButton {
  func alignVertical(spacing: CGFloat = 6.0) {
    guard let imageSize = imageView?.image?.size,
      let text = titleLabel?.text,
      let font = titleLabel?.font
    else { return }

    titleEdgeInsets = UIEdgeInsets(
      top: 0.0,
      left: -imageSize.width,
      bottom: -(imageSize.height + spacing),
      right: 0.0
    )

    let titleSize = text.size(withAttributes: [.font: font])
    imageEdgeInsets = UIEdgeInsets(
      top: -(titleSize.height + spacing),
      left: 0.0,
      bottom: 0.0, right: -titleSize.width
    )

    let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0
    contentEdgeInsets = UIEdgeInsets(
      top: edgeOffset,
      left: 0.0,
      bottom: edgeOffset,
      right: 0.0
    )
  }
}

5
Meraviglioso - grazie! Penso che molte altre risposte vadano su questo "nel modo più duro" - sembra molto meglio.
Joe D'Andrea,

3
Ho trovato quanto sopra da svegliare, ma non ho assolutamente alcun modello mentale per come. Qualcuno ha un link a una spiegazione pittorica di quali elementi influenzano i singoli parametri EdgeInsets? E perché la larghezza del testo sarebbe cambiata?
Robert Atkins,

3
Questo non funziona quando l'immagine viene ridotta per adattarla al pulsante. Sembra che UIButton (almeno in iOS 7) usi image.size, non imageView.frame.size per i suoi calcoli di centratura.
Dan Jackson,

5
@Hemang e Dan Jackson, sto incorporando i tuoi suggerimenti senza testarli da solo. Trovo ridicolo che in origine lo abbia scritto per iOS 4, e dopo molte versioni dobbiamo ancora essenzialmente decodificare l'algoritmo di layout di Apple per ottenere una funzionalità così ovvia. O almeno suppongo che non esista ancora una soluzione migliore dal flusso coerente di voti positivi e dalle risposte ugualmente hackerate di seguito (nessun insulto previsto).
Jesse Crossen,

5
In iOS8, ho trovato migliore da usare button.currentTitleinvece che button.titleLabel.textsoprattutto se il testo del pulsante cambierà mai. currentTitleviene popolato immediatamente, mentre titleLabel.textpuò essere lento a cambiare, il che può portare a inserti non allineati.
mjangda,

59

Trovato come.

Innanzitutto, configura il testo di titleLabel(a causa di stili, ad esempio grassetto, corsivo, ecc.). Quindi, utilizza setTitleEdgeInsetsconsiderando la larghezza della tua immagine:

[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:title forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont boldSystemFontOfSize:10.0]];

// Left inset is the negative of image width.
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, -image.size.width, -25.0, 0.0)]; 

Successivamente, utilizza setTitleEdgeInsetsconsiderando la larghezza dei limiti del testo:

[button setImage:image forState:UIControlStateNormal];

// Right inset is the negative of text bounds width.
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, -button.titleLabel.bounds.size.width)];

Ora l'immagine e il testo saranno centrati (in questo esempio l'immagine appare sopra il testo).

Saluti.


3
7 anni, amico. Davvero non ricordo. Quando ho chiesto, ho risposto a me stesso (la mia risposta era l'unica al momento). Ho cambiato la risposta selezionata quando l'autore dell'attuale risposta selezionata si è concentrato sull'eliminazione di quei numeri magici. Quindi, nella risposta selezionata, puoi capire cosa significano.
Reinaldoluckman,

20

Puoi farlo con questa estensione Swift, che si basava in parte sulla risposta di Jesse Crossen:

extension UIButton {
  func centerLabelVerticallyWithPadding(spacing:CGFloat) {
    // update positioning of image and title
    let imageSize = self.imageView.frame.size
    self.titleEdgeInsets = UIEdgeInsets(top:0,
                                        left:-imageSize.width,
                                        bottom:-(imageSize.height + spacing),
                                        right:0)
    let titleSize = self.titleLabel.frame.size
    self.imageEdgeInsets = UIEdgeInsets(top:-(titleSize.height + spacing),
                                        left:0,
                                        bottom: 0,
                                        right:-titleSize.width)

    // reset contentInset, so intrinsicContentSize() is still accurate
    let trueContentSize = CGRectUnion(self.titleLabel.frame, self.imageView.frame).size
    let oldContentSize = self.intrinsicContentSize()
    let heightDelta = trueContentSize.height - oldContentSize.height
    let widthDelta = trueContentSize.width - oldContentSize.width
    self.contentEdgeInsets = UIEdgeInsets(top:heightDelta/2.0,
                                          left:widthDelta/2.0,
                                          bottom:heightDelta/2.0,
                                          right:widthDelta/2.0)
  }
}

Questo definisce una funzione centerLabelVerticallyWithPaddingche imposta il titolo e le immagini in modo appropriato.

Imposta anche contentEdgeInsets, che credo sia necessario per garantire che funzioni intrinsicContentSizeancora correttamente, che dovrebbe utilizzare Auto Layout.

Credo che tutte le soluzioni che sottoclassano UIButton siano tecnicamente illegittime, dal momento che non si suppone che debbano sottoclassare i controlli UIKit. Cioè, in teoria potrebbero rompersi nelle versioni future.


Test su iOS9. L'immagine appare centrata, ma il testo appare a sinistra :(
endavid

13

Modifica: aggiornato per Swift 3

Se stai cercando una soluzione rapida della risposta di Jesse Crossen, puoi aggiungerla a una sottoclasse di UIButton:

override func layoutSubviews() {

    let spacing: CGFloat = 6.0

    // lower the text and push it left so it appears centered
    //  below the image
    var titleEdgeInsets = UIEdgeInsets.zero
    if let image = self.imageView?.image {
        titleEdgeInsets.left = -image.size.width
        titleEdgeInsets.bottom = -(image.size.height + spacing)
    }
    self.titleEdgeInsets = titleEdgeInsets

    // raise the image and push it right so it appears centered
    //  above the text
    var imageEdgeInsets = UIEdgeInsets.zero
    if let text = self.titleLabel?.text, let font = self.titleLabel?.font {
        let attributes = [NSFontAttributeName: font]
        let titleSize = text.size(attributes: attributes)
        imageEdgeInsets.top = -(titleSize.height + spacing)
        imageEdgeInsets.right = -titleSize.width
    }
    self.imageEdgeInsets = imageEdgeInsets

    super.layoutSubviews()
}

9

Ci sono alcuni ottimi esempi qui, ma non sono riuscito a farlo funzionare in tutti i casi quando ho a che fare anche con più righe di testo (a capo automatico). Per finalmente farlo funzionare ho combinato un paio di tecniche:

  1. Ho usato l'esempio di Jesse Crossen sopra. Tuttavia, ho risolto un problema di altezza del testo e ho aggiunto la possibilità di specificare un margine di testo orizzontale. Il margine è utile quando si consente di avvolgere il testo in modo che non colpisca il bordo del pulsante:

    // the space between the image and text
    CGFloat spacing = 10.0;
    float   textMargin = 6;
    
    // get the size of the elements here for readability
    CGSize  imageSize   = picImage.size;
    CGSize  titleSize   = button.titleLabel.frame.size;
    CGFloat totalHeight = (imageSize.height + titleSize.height + spacing);      // get the height they will take up as a unit
    
    // lower the text and push it left to center it
    button.titleEdgeInsets = UIEdgeInsetsMake( 0.0, -imageSize.width +textMargin, - (totalHeight - titleSize.height), +textMargin );   // top, left, bottom, right
    
    // the text width might have changed (in case it was shortened before due to 
    // lack of space and isn't anymore now), so we get the frame size again
    titleSize = button.titleLabel.bounds.size;
    
    button.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + spacing), 0.0, 0.0, -titleSize.width );     // top, left, bottom, right        
  2. Assicurati di impostare l'etichetta di testo da avvolgere

    button.titleLabel.numberOfLines = 2; 
    button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
    button.titleLabel.textAlignment = UITextAlignmentCenter;
  3. Ora funzionerà principalmente. Tuttavia, avevo alcuni pulsanti che non avrebbero reso la loro immagine correttamente. L'immagine è stata spostata a destra o a sinistra (non era centrata). Quindi ho usato una tecnica di override del layout UIButton per forzare il centraggio di imageView.

    @interface CategoryButton : UIButton
    @end
    
    @implementation CategoryButton
    
    - (void)layoutSubviews
    {
        // Allow default layout, then center imageView
        [super layoutSubviews];
    
        UIImageView *imageView = [self imageView];
        CGRect imageFrame = imageView.frame;
        imageFrame.origin.x = (int)((self.frame.size.width - imageFrame.size.width)/ 2);
        imageView.frame = imageFrame;
    }
    @end

Sembra che questa sia una buona soluzione, tuttavia button.titleLabel.numberOfLines non dovrebbe essere 0 in modo tale che possa avere tutte le righe che vuole?
Ben Lachman,

Nel mio caso, volevo solo fino a due righe. Altrimenti, l'immagine avrebbe problemi con la dimensione complessiva del pulsante.
Tod Cunningham,

9

Ho creato un metodo per la risposta di @ TodCunningham

 -(void) AlignTextAndImageOfButton:(UIButton *)button
 {
   CGFloat spacing = 2; // the amount of spacing to appear between image and title
   button.imageView.backgroundColor=[UIColor clearColor];
   button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
   button.titleLabel.textAlignment = UITextAlignmentCenter;
   // get the size of the elements here for readability
   CGSize imageSize = button.imageView.frame.size;
   CGSize titleSize = button.titleLabel.frame.size;

  // lower the text and push it left to center it
  button.titleEdgeInsets = UIEdgeInsetsMake(0.0, - imageSize.width, - (imageSize.height   + spacing), 0.0);

  // the text width might have changed (in case it was shortened before due to 
  // lack of space and isn't anymore now), so we get the frame size again
   titleSize = button.titleLabel.frame.size;

  // raise the image and push it right to center it
  button.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0.0, 0.0, -     titleSize.width);
 }

7

Aggiornato per Xcode 11+

Gli inserti descritti nella mia risposta originale sono stati spostati nella finestra di ispezione delle dimensioni nelle versioni più recenti di Xcode. Non sono sicuro al 100% su quando è avvenuta la commutazione, ma i lettori dovrebbero rivedere l'ispettore dimensioni se le informazioni sull'inserimento non sono state trovate nell'ispettore attributi. Di seguito è riportato un esempio della nuova schermata di inserimento (situata nella parte superiore della finestra di ispezione degli attributi di dimensione a partire da 11.5).

insets_moved_to_size_inspector

Risposta originale

Nulla di sbagliato con le altre risposte, tuttavia volevo solo notare che lo stesso comportamento può essere realizzato visivamente all'interno di Xcode usando zero righe di codice. Questa soluzione è utile se non hai bisogno di un valore calcolato o stai costruendo con uno storyboard / xib (altrimenti si applicano altre soluzioni).

Nota: capisco che la domanda del PO è una richiesta di codice. Sto solo fornendo questa risposta per completezza e come alternativa logica per coloro che usano storyboard / xibs.

Per modificare la spaziatura su immagini, titoli e visualizzazioni del contenuto di un pulsante utilizzando gli inserti dei bordi, è possibile selezionare il pulsante / controllo e aprire la finestra di ispezione degli attributi. Scorri verso il basso verso il centro della finestra di ispezione e trova la sezione per gli inserti Edge.

edge-inserti

Si può anche accedere e modificare gli inserti di bordo specifici per il titolo, l'immagine o la vista del contenuto.

menu-opzioni


Quello che non capisco è perché non riesco a inserire numeri negativi nello storyboard per alcuni valori.
Daniel T.

Funziona con la nuova versione rapida? Non riesco a trovare l'attributo Edge da nessuna parte
brockhampton il

@brockhampton - vedi la risposta aggiornata per la nuova posizione
Tommie C.

6

Non combattere il sistema. Se i tuoi layout diventano troppo complessi da gestire usando Interface Builder + forse un semplice codice di configurazione, esegui i layout manualmente in un modo più semplice usando layoutSubviews- questo è quello che serve! Tutto il resto equivale a hack.

Creare una sottoclasse UIButton e sovrascriverne il layoutSubviewsmetodo per allineare il testo e l'immagine a livello di codice. Oppure usa qualcosa come https://github.com/nickpaulson/BlockKit/blob/master/Source/UIView-BKAdditions.h in modo da poter implementare layoutSubviews usando un blocco.


6

UIButton sottoclasse

- (void)layoutSubviews {
    [super layoutSubviews];
    CGFloat spacing = 6.0;
    CGSize imageSize = self.imageView.image.size;
    CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(self.frame.size.width, self.frame.size.height - (imageSize.height + spacing))];
    self.imageView.frame = CGRectMake((self.frame.size.width - imageSize.width)/2, (self.frame.size.height - (imageSize.height+spacing+titleSize.height))/2, imageSize.width, imageSize.height);
    self.titleLabel.frame = CGRectMake((self.frame.size.width - titleSize.width)/2, CGRectGetMaxY(self.imageView.frame)+spacing, titleSize.width, titleSize.height);
}

6

Risposta aggiornata di Jesse Crossen per Swift 4 :

extension UIButton {
    func alignVertical(spacing: CGFloat = 6.0) {
        guard let imageSize = self.imageView?.image?.size,
            let text = self.titleLabel?.text,
            let font = self.titleLabel?.font
            else { return }
        self.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + spacing), right: 0.0)
        let labelString = NSString(string: text)
        let titleSize = labelString.size(withAttributes: [kCTFontAttributeName as NSAttributedStringKey: font])
        self.imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width)
        let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
        self.contentEdgeInsets = UIEdgeInsets(top: edgeOffset, left: 0.0, bottom: edgeOffset, right: 0.0)
    }
}

Usa in questo modo:

override func viewDidLayoutSubviews() {
    button.alignVertical()
}

Dopo molte, molte ore. Questa è stata l'unica cosa che ha funzionato :)
Harry Blue

4

Con questo pezzo di codice, otterrai qualcosa del genere allineamento del titolo e dell'immagine

extension UIButton {
    func alignTextUnderImage() {
        guard let imageView = imageView else {
                return
        }
        self.contentVerticalAlignment = .Top
        self.contentHorizontalAlignment = .Center
        let imageLeftOffset = (CGRectGetWidth(self.bounds) - CGRectGetWidth(imageView.bounds)) / 2//put image in center
        let titleTopOffset = CGRectGetHeight(imageView.bounds) + 5
        self.imageEdgeInsets = UIEdgeInsetsMake(0, imageLeftOffset, 0, 0)
        self.titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset, -CGRectGetWidth(imageView.bounds), 0, 0)
    }
}

2
Ho scritto una piccola estensione per posizionare l'immagine e il testo all'interno del pulsante. Se sei interessato, ecco il codice sorgente. github.com/sssbohdan/ButtonAlignmentExtension/blob/master/…
Bohdan Savych

4

Estensione UIButton con sintassi Swift 3+ :

extension UIButton {
    func alignImageAndTitleVertically(padding: CGFloat = 6.0) {
        let imageSize: CGSize = imageView!.image!.size
        titleEdgeInsets = UIEdgeInsetsMake(0.0, -imageSize.width, -(imageSize.height + padding), 0.0)
        let labelString = NSString(string: titleLabel!.text!)
        let titleSize = labelString.size(attributes: [NSFontAttributeName: titleLabel!.font])
        self.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + padding), 0.0, 0.0, -titleSize.width)
        let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
        self.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0)
    }
}

Risposta originale: https://stackoverflow.com/a/7199529/3659227


3

Solo una piccola modifica alla risposta di Jesse Crossen che l'ha fatto funzionare perfettamente per me:

invece di:

CGSize titleSize = button.titleLabel.frame.size;

Ho usato questo:

CGSize titleSize = [button.titleLabel.text sizeWithAttributes: @{NSFontAttributeName:button.titleLabel.font}];

Benvenuti in SO! Invece di aggiungere una risposta separata (per una modifica minore) puoi scriverla direttamente a Jesse in modo che possa controllare e aggiornare correttamente la sua risposta [accettata] (se necessario).
Hemang,

3

L'uso button.titleLabel.frame.size.widthfunziona bene solo finché l'etichetta è abbastanza corta da non essere troncata. Tuttavia, quando il testo dell'etichetta viene troncato, il posizionamento non funziona. Prendere

CGSize titleSize = [[[button titleLabel] text] sizeWithFont:[[button titleLabel] font]];

funziona per me anche quando il testo dell'etichetta viene troncato.


hai un errore di battitura.
Bhimbim,

2

Ho esaminato le risposte esistenti ma ho anche scoperto che l'impostazione della cornice dei pulsanti è un primo passo importante.

Ecco una funzione che uso che si occupa di questo:

const CGFloat kImageTopOffset   = -15;
const CGFloat kTextBottomOffset = -25;

+ (void) centerButtonImageTopAndTextBottom: (UIButton*)         button 
                                     frame: (CGRect)            buttonFrame
                                      text: (NSString*)         textString
                                 textColor: (UIColor*)          textColor
                                      font: (UIFont*)           textFont
                                     image: (UIImage*)          image
                                  forState: (UIControlState)    buttonState
{
    button.frame = buttonFrame;

    [button setTitleColor: (UIColor*)       textColor
                 forState: (UIControlState) buttonState];

    [button setTitle: (NSString*) textString
            forState: (UIControlState) buttonState ];


    [button.titleLabel setFont: (UIFont*) textFont ];

    [button setTitleEdgeInsets: UIEdgeInsetsMake( 0.0, -image.size.width, kTextBottomOffset,  0.0)]; 

    [button setImage: (UIImage*)       image 
            forState: (UIControlState) buttonState ];

    [button setImageEdgeInsets: UIEdgeInsetsMake( kImageTopOffset, 0.0, 0.0,- button.titleLabel.bounds.size.width)];
}

2

Oppure puoi semplicemente usare questa categoria:

@interface UIButton (VerticalLayout)  

- (void)centerVerticallyWithPadding:(float)padding;  
- (void)centerVertically;  

@end  


@implementation UIButton (VerticalLayout)  

- (void)centerVerticallyWithPadding:(float)padding 
{      
    CGSize imageSize = self.imageView.frame.size;  
    CGSize titleSize = self.titleLabel.frame.size;  

    CGFloat totalHeight = (imageSize.height + titleSize.height + padding);  

    self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height),
                                            0.0f,
                                            0.0f,
                                            - titleSize.width);

    self.titleEdgeInsets = UIEdgeInsetsMake(0.0f,
                                            - imageSize.width,
                                            - (totalHeight - titleSize.height),
                                            0.0f);

}


- (void)centerVertically
{  
    const CGFloat kDefaultPadding = 6.0f;

    [self centerVerticallyWithPadding:kDefaultPadding];  
}  


@end

1
Questo non funzionerebbe con caratteri personalizzati. Da iOS7 +,CGSize titleSize = [button.titleLabel.text sizeWithAttributes: @{NSFontAttributeName: button.titleLabel.font}];
Hemang

1

Il mio caso d'uso ha reso le inserzioni ingestibili:

  1. l'immagine di sfondo sul pulsante rimane coerente
  2. testo dinamico e immagine cambiano dove variano la lunghezza della stringa e la dimensione dell'immagine

Questo è quello che ho finito per fare e ne sono abbastanza contento:

  • Crea il pulsante sullo storyboard con un'immagine di sfondo (cerchio rotondo con sfocatura e colore).

  • Dichiara un UIImageView nella mia classe:

    @implementation BlahViewController {
        UIImageView *_imageView;
    }
  • Crea istanza di visualizzazione immagine su init:

    -(id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            _imageView = [[UIImageView alloc] initWithCoder:aDecoder];
         }
         return self;
     }
  • In viewDidLoad aggiungi un nuovo livello al pulsante per la nostra vista immagine e imposta l'allineamento del testo:

    [self.btn addSubview:_imageView];
    [self.btn.titleLabel setTextAlignment:NSTextAlignmentCenter];
  • Nel metodo del clic sul pulsante aggiungi l'immagine sovrapposta prescelta alla vista immagine, ridimensionala per adattarla all'immagine e centrala nel pulsante ma spostala verso l'alto 15 in modo da poter posizionare l'offset del testo al di sotto di esso:

    [_imageView setImage:[UIImage imageNamed:@"blahImageBlah]];
    [_imageView sizeToFit];
    _imageView.center = CGPointMake(ceilf(self.btn.bounds.size.width / 2.0f),
             ceilf((self.btn.bounds.size.height / 2.0f) - 15));
    [self.btn setTitle:@"Some new text" forState:UIControlStateNormal];

Nota: ceilf () è importante per assicurarsi che si trovi su un limite di pixel per la qualità dell'immagine.


1
Sicuramente un approccio migliore anche per il mio caso d'uso poiché sto aggiungendo il pulsante a una vista pila.
valeCocoa,

0

Supponendo che si desideri centrare sia il testo che l'immagine in orizzontale, l'immagine sopra il testo: centrare il testo dal generatore di interfacce e aggiungere un inserto superiore (facendo spazio all'immagine). (lasciare l'inserzione sinistra su 0). Usa il generatore di interfacce per scegliere l'immagine: la sua posizione effettiva sarà impostata dal codice, quindi non preoccuparti che le cose non sembrino ok in IB. A differenza di altre risposte sopra, questo funziona in realtà su tutte le versioni iOS attualmente supportate (5,6 e 7).

Nel codice, basta scartare ImageView del pulsante (impostando l'immagine del pulsante su null) dopo aver catturato l'immagine (ciò centrerà automaticamente anche il testo, se necessario avvolto). Quindi crea un'istanza di ImageView con le stesse dimensioni e immagine dello stesso frame e posizionalo al centro.

In questo modo puoi comunque scegliere l'immagine dal generatore di interfacce (anche se non sarà allineato in IB come nel simulatore, ma poi, altre soluzioni non sono compatibili con tutte le versioni di ios supportate)


0

Stavo lottando per farlo perché non riuscivo a ottenere la dimensione dell'immagine e la larghezza del testo sul costruttore della mia vista. Due piccole modifiche alla risposta di Jesse hanno funzionato per me:

CGFloat spacing = 3;
self.titleEdgeInsets = UIEdgeInsetsMake(0.0, - image.size.width, - (image.size.height + spacing), 0.0);
CGSize titleSize = [name sizeWithAttributes:@{NSFontAttributeName:self.titleLabel.font}];
self.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

Le modifiche sono:

  • utilizzando [NSString sizeWithAttributes] per ottenere la larghezza del testo;
  • Ottieni le dimensioni dell'immagine direttamente sul UIImageanzichéUIImageView

0

Questo funziona bene per me, per diversi pulsanti, con diversa larghezza dell'immagine e diversa lunghezza del titolo:

sottoclasse UIButton

override func layoutSubviews() {
    super.layoutSubviews()

    if let image = imageView?.image {

        let margin = 30 - image.size.width / 2
        let titleRect = titleRectForContentRect(bounds)
        let titleOffset = (bounds.width - titleRect.width - image.size.width - margin) / 2


        contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
            imageEdgeInsets = UIEdgeInsetsMake(0, margin, 0, 0)
            titleEdgeInsets = UIEdgeInsetsMake(0, (bounds.width - titleRect.width -  image.size.width - margin) / 2, 0, 0)
    }

}

0

Funziona bene per le dimensioni del pulsante 80x80 pixel.

[self.leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, 10.0, 20.0, 10.0)];    
[self.leftButton setTitleEdgeInsets:UIEdgeInsetsMake(60, -75.0, 0.0, 0.0)];

0

Ho apportato alcune modifiche per allineare l'immagine al centro orizzontale:

// the space between the image and text
        let spacing = CGFloat(36.0);

        // lower the text and push it left so it appears centered
        //  below the image
        let imageSize = tutorialButton.imageView!.frame.size;
        tutorialButton.titleEdgeInsets = UIEdgeInsetsMake(
            0, -CGFloat(imageSize.width), -CGFloat(imageSize.height + spacing), 0.0);

        // raise the image and push it right so it appears centered
        //  above the text
        let titleSize = tutorialButton.titleLabel!.frame.size;
        tutorialButton.imageEdgeInsets = UIEdgeInsetsMake(
            -CGFloat(titleSize.height + spacing), CGFloat((tutorialButton.frame.width - imageSize.width) / 2), 0.0, -CGFloat(titleSize.width));

0

è obbligatorio utilizzare inserti perimetrali? In caso contrario, puoi provare a posizionare rispetto alla vista genitore centrale

extension UIButton 
{
    func centerImageAndTextVerticaAlignment(spacing: CGFloat) 
    {
        var titlePoint : CGPoint = convertPoint(center, fromView:superview)
        var imageViewPoint : CGPoint = convertPoint(center, fromView:superview)
        titlePoint.y += ((titleLabel?.size.height)! + spacing)/2
        imageViewPoint.y -= ((imageView?.size.height)! + spacing)/2
        titleLabel?.center = titlePoint
        imageView?.center = imageViewPoint

    }
}

La domanda chiede esplicitamente l'uso di imageEdgeInsets e titleEdgeInsets, quindi è probabile che sia obbligatorio
Tibrogargan,

0

Devi spostare l'immagine a destra della larghezza del testo. Quindi sposta il testo a sinistra della larghezza dell'immagine.

UIEdgeInsets imageEdgeInsets = self.remoteCommandsButtonLights.imageEdgeInsets;
imageEdgeInsets.left = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:[button.titleLabel font]}].width;
imageEdgeInsets.bottom = 14.0;
button.imageEdgeInsets = imageEdgeInsets;

UIEdgeInsets titleEdgeInsets = self.remoteCommandsButtonLights.titleEdgeInsets;
titleEdgeInsets.left = -button.currentImage.size.width;
titleEdgeInsets.top = 20.0;
button.titleEdgeInsets = titleEdgeInsets;

Quindi regolare gli inserti superiore e inferiore per regolare l'asse Y. Probabilmente questo potrebbe essere fatto anche a livello di codice, ma dovrebbe essere costante per le dimensioni dell'immagine. Considerando che gli inserti dell'asse X dovranno cambiare in base alla dimensione dell'etichetta di testo in ciascun pulsante.


0

Aggiungi questo codice nell'estensione Swift 4.2

 func moveImageLeftTextCenter(imagePadding: CGFloat = 30.0){
    guard let imageViewWidth = self.imageView?.frame.width else{return}
    guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
    self.contentHorizontalAlignment = .left
    imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imagePadding - imageViewWidth / 2, bottom: 0.0, right: 0.0)
    titleEdgeInsets = UIEdgeInsets(top: 0.0, left: (bounds.width - titleLabelWidth) / 2 - imageViewWidth, bottom: 0.0, right: 0.0)
}
func moveImageRIghtTextCenter(imagePadding: CGFloat = 30.0){
    guard let imageViewWidth = self.imageView?.frame.width else{return}
    guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
    self.contentHorizontalAlignment = .right
    imageEdgeInsets = UIEdgeInsets(top: 0.0, left:0.0 , bottom: 0.0, right: imagePadding - imageViewWidth / 2)
    titleEdgeInsets = UIEdgeInsets(top: 0.0, left:0.0 , bottom: 0.0, right:(bounds.width - titleLabelWidth) / 2 - imageViewWidth)
}

0

Solo per buttare dentro i miei 2 centesimi, questo ha funzionato per me:

extension UIButton {
  public func centerImageAndTextVertically(spacing: CGFloat) {
    layoutIfNeeded()
    let contentFrame = contentRect(forBounds: bounds)
    let imageFrame = imageRect(forContentRect: contentFrame)
    let imageLeftInset = bounds.size.width * 0.5 - imageFrame.size.width * 0.5
    let imageTopInset = -(imageFrame.size.height + spacing * 0.5)
    let titleFrame = titleRect(forContentRect: contentFrame)
    let titleLeftInset = ((bounds.size.width - titleFrame.size.width) * 0.5) - imageFrame.size.width
    let titleTopInmset = titleFrame.size.height + spacing * 0.5
    imageEdgeInsets = UIEdgeInsets(top: imageTopInset, left: imageLeftInset, bottom: 0, right: 0)
    titleEdgeInsets = UIEdgeInsets(top: titleTopInmset, left: titleLeftInset, bottom: 0, right: 0)
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.