UIButton: jak wyśrodkować obraz i tekst za pomocą imageEdgeInsets i titleEdgeInsets?

Jeśli umieszczę tylko obrazek w przycisku i ustawię imageEdgeInsets bliżej góry, obrazek pozostanie wyśrodkowany i wszystko działa zgodnie z oczekiwaniami:

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

Jeśli umieszczę tylko tekst w przycisku i ustawię titleEdgeInsets bliżej dołu, tekst pozostanie wyśrodkowany i wszystko działa zgodnie z oczekiwaniami:

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

Ale jeśli złożę 4 linie razem, tekst zakłóci obraz i oba utracą wyrównanie środkowe.

Wszystkie moje zdjęcia mają szerokość 30 pikseli, a jeśli włożę 30 w lewo parametr UIEdgeInsetMake dla setTitleEdgeInsets tekst jest ponownie wyśrodkowany. Problem polega na tym, że obraz nigdy nie jest wyśrodkowany, ponieważ wydaje się, że jest zależny od przycisku.rozmiar etykietki tytułowej. Próbowałem już wielu obliczeń z rozmiarem przycisku, rozmiarem obrazu, rozmiarem etykiet titleLabel i nigdy nie uzyskałem idealnego wyśrodkowania.

Ktoś już miał ten sam problem?
Author: Pang, 2010-03-16

24 answers

Jeśli to coś warte, oto ogólne rozwiązanie, aby umieścić obraz na środku tekstu bez użycia magicznych liczb. zauważ, że poniższy kod jest nieaktualny i prawdopodobnie powinieneś użyć jednej z zaktualizowanych wersji poniżej :

// 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);

Poniższa wersja zawiera zmiany w obsłudzeiOS 7+, które zostały zalecane w komentarzach poniżej. Sam nie testowałem tego kodu, więc nie jestem pewien, jak dobrze to działa, ani czy by się zepsuł, gdyby był używany pod poprzednim wersje 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);

Swift version

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(attributes: [NSFontAttributeName: 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)
  }
}
 394
Author: Jesse Crossen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-11 04:01:45

Znalazłem jak.

Najpierw skonfiguruj tekst titleLabel (ze względu na style, tj. Następnie użyj setTitleEdgeInsets biorąc pod uwagę szerokość obrazu:

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

Następnie użyj setTitleEdgeInsets biorąc pod uwagę szerokość granic tekstu:

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

Teraz obrazek i tekst zostaną wyśrodkowane (w tym przykładzie obrazek pojawia się nad tekstem).

Zdrówko.
 58
Author: reinaldoluckman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-29 07:10:30

Możesz to zrobić za pomocą tego rozszerzenia Swift, które zostało częściowo oparte na odpowiedzi Jesse Crossena:

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)
  }
}

Definiuje funkcję centerLabelVerticallyWithPadding, która odpowiednio ustawia wstawianie tytułu i obrazu.

Ustawia również contentEdgeInsets, co moim zdaniem jest konieczne, aby upewnić się, że intrinsicContentSize nadal działa poprawnie, co wymagałoby użycia układu Auto.

Uważam, że wszystkie rozwiązania, które są podklasą UIButton są technicznie nielegalne, ponieważ nie powinieneś podklasować UIKit sterowanie. Tzn. teoretycznie mogą się zepsuć w przyszłych wydaniach.

 20
Author: algal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-18 21:11:33

Edit: Updated for Swift 3

Jeśli szukasz szybkiego rozwiązania odpowiedzi Jesse Crossena, możesz dodać to do podklasy 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()
}
 12
Author: Thomas Verbeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-07 04:41:49

Jest tu kilka świetnych przykładów, ale nie mogłem tego zrobić we wszystkich przypadkach, gdy zajmowałem się również wieloma wierszami tekstu (owijanie tekstu). Aby w końcu zacząć działać, połączyłem kilka technik:

  1. Użyłem przykładu Jesse Crossen powyżej. Jednak poprawiłem wysokość tekstu problem i dodałem możliwość określenia poziomego marginesu tekstu. Margines jest przydatny, gdy pozwala na zawijanie tekstu, aby nie uderzył the edge of the "button": {]}

    // 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. Upewnij się, że ustawiłeś etykietę tekstową do zawijania

    button.titleLabel.numberOfLines = 2; 
    button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
    button.titleLabel.textAlignment = UITextAlignmentCenter;
    
  3. To w większości zadziała teraz. Miałem jednak kilka przycisków, które nie renderowały poprawnie ich obrazu. Obraz był albo przesunięty daleko w prawo, albo w lewo (nie był wyśrodkowany). Więc użyłem techniki obejścia układu UIButton, aby wymusić wyśrodkowanie 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
    
 9
Author: Tod Cunningham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-27 18:38:45

Zrobiłem metodę na odpowiedź @ 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);
 }
 9
Author: Bekir Onat Akin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-28 11:38:33

Nie walcz z systemem. Jeśli Twoje layouty stają się zbyt skomplikowane, aby zarządzać za pomocą narzędzia Interface Builder + może prostego kodu konfiguracyjnego, wykonaj je ręcznie w prostszy sposób za pomocą layoutSubviews - po to to jest! Wszystko inne będzie sumować się do hacków.

Utwórz podklasę UIButton i Nadpisz jej metodę layoutSubviews, aby programowo wyrównać tekst i obraz. Lub użyć czegoś w rodzaju https://github.com/nickpaulson/BlockKit/blob/master/Source/UIView-BKAdditions.h więc możesz implementacja layoutSubviews za pomocą bloku.

 6
Author: Steven Kramer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-01 14:06:07

Podklasa UIButton

- (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);
}
 5
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-23 14:12:24

Nic złego z innymi odpowiedziami, jednak chciałem tylko zauważyć, że to samo zachowanie można osiągnąć wizualnie w Xcode za pomocą zerowych linii kodu. To rozwiązanie jest przydatne, jeśli nie potrzebujesz obliczonej wartości lub budujesz za pomocą storyboard / xib (w przeciwnym razie zastosowanie mają inne rozwiązania).

Uwaga-rozumiem, że pytanie OP wymaga kodu. Podaję tylko tę odpowiedź dla kompletności i jako logiczną alternatywę dla tych, którzy używają storyboards / xibs.

Aby zmodyfikować odstępy w widokach obrazu, tytułu i zawartości przycisku za pomocą wstawek krawędzi, można wybrać przycisk / sterowanie i otworzyć Inspektora atrybutów. Przewiń w dół w kierunku środka inspektora i znajdź sekcję wstawiania krawędzi.

wkładki krawędziowe

Można również uzyskać dostęp i modyfikować określone wstawki krawędzi dla widoku tytuł, obraz lub zawartość .

menu-Opcje

 5
Author: Tommie C.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-06 18:06:57

Rozszerzenie UIButton z Swift 3+ składnia:

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)
    }
}

Oryginalna ODPOWIEDŹ: https://stackoverflow.com/a/7199529/3659227

 4
Author: Maverick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 10:17:16

Tylko drobna zmiana w odpowiedzi Jesse Crossena, która sprawiła, że działa idealnie dla mnie:

Zamiast:

CGSize titleSize = button.titleLabel.frame.size;

Użyłem tego:

CGSize titleSize = [button.titleLabel.text sizeWithAttributes: @{NSFontAttributeName:button.titleLabel.font}];
 3
Author: Cesar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-22 12:58:41

Z tym kawałkiem kodu otrzymasz coś takiego wyrównanie tytułu i obrazu

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)
    }
}
 3
Author: Bohdan Savych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-04 08:55:03

Użycie button.titleLabel.frame.size.width działa dobrze tylko wtedy, gdy etykieta jest wystarczająco krótka, aby nie zostać obcięta. Gdy tekst etykiety zostanie obcięty, pozycjonowanie nie działa. Biorąc

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

Działa dla mnie nawet wtedy, gdy tekst etykiety jest obcięty.

 3
Author: dezember,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-07 07:36:30

Przyjrzałem się istniejącym odpowiedziom, ale odkryłem również, że ustawienie ramki przycisku jest ważnym pierwszym krokiem.

Oto funkcja, której używam, która zajmuje się tym:

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
Author: Bamaco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-01 16:19:41

Lub możesz po prostu użyć tej kategorii:

@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
 2
Author: RaffAl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-24 22:07:00

Mój przypadek użycia sprawił, że wstawianie nie było możliwe:

  1. obraz tła na przycisku pozostaje spójny
  2. dynamiczny tekst i obraz zmienia się tam, gdzie zmienia się długość łańcucha i rozmiar obrazu

Tak się skończyło i jestem z tego całkiem zadowolony:

  • Utwórz przycisk na storyboardzie z obrazem tła (okrągłe koło z rozmyciem i kolorem).

  • Zadeklaruj UIImageView w mojej klasie:

    @implementation BlahViewController {
        UIImageView *_imageView;
    }
    
  • Tworzenie widoku obrazu instancja na init:

    -(id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            _imageView = [[UIImageView alloc] initWithCoder:aDecoder];
         }
         return self;
     }
    
  • W viewDidLoad Dodaj nową warstwę do przycisku dla naszego widoku obrazu i ustaw wyrównanie tekstu:

    [self.btn addSubview:_imageView];
    [self.btn.titleLabel setTextAlignment:NSTextAlignmentCenter];
    
  • W metodzie button click dodaj wybrany obraz nakładki do widoku obrazu, dostosuj rozmiar do obrazu i wyśrodkuj go w przycisku, ale przesuń go w górę o 15, abym mógł umieścić przesunięcie tekstu pod nim:

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

Uwaga: ceilf() jest ważne, aby upewnić się, że jest na granicy pikseli dla jakości obrazu.

 1
Author: Oliver Dungey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-02 17:57:18

[[2]] zaktualizowana odpowiedź z Jesse Crossen dla 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)
    }
}

Użyj w ten sposób:

override func viewDidLayoutSubviews() {
    button.alignVertical()
}
 1
Author: DocPllana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-15 15:42:51

Zakładając, że chcesz, aby zarówno tekst, jak i obrazek były wyśrodkowane poziomo, obrazek nad tekstem: Wyśrodkuj tekst z narzędzia interface builder i dodaj górną wstawkę(robiąc miejsce na obraz). (pozostawić lewą wstawkę na 0). Użyj kreatora interfejsu, aby wybrać obraz-jego rzeczywista pozycja zostanie ustawiona z kodu, więc nie martw się, że w IB nie będzie dobrze wyglądać. W przeciwieństwie do innych powyższych odpowiedzi, działa to we wszystkich aktualnie obsługiwanych wersjach ios(5,6 i 7).

W kodzie po prostu Odrzuć ImageView przycisku (ustawiając obraz przycisku na null) po pobraniu obrazu (spowoduje to również automatyczne wyśrodkowanie tekstu, zawinięte w razie potrzeby). Następnie utwórz instancję własnego obrazu ImageView o tym samym rozmiarze klatki i obrazu i umieść go pośrodku.

W ten sposób można nadal wybrać obraz z interface builder (choć nie będzie wyrównany w IB jak w symulatorze, ale z drugiej strony inne rozwiązania nie są kompatybilne we wszystkich obsługiwanych wersjach ios)

 0
Author: Radu Simionescu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-04 22:37:58

Starałem się to zrobić, ponieważ nie mogłem uzyskać rozmiaru obrazu i szerokości tekstu w konstruktorze widoku. Dwie drobne zmiany na odpowiedź Jesse ' ego zadziałała dla mnie:

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

Zmiana to:

  • Using [NSString sizeWithAttributes] to get text width;
  • uzyskaj Rozmiar obrazu bezpośrednio na UIImage zamiast UIImageView
 0
Author: saulobrito,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:25

To działa dobrze dla mnie, dla kilku przycisków, o różnej szerokości obrazu i różnej długości tytułu:

Podklasa 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
Author: Rémy Virin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-25 09:41:07

Działa dobrze dla przycisku o rozmiarze 80x80 pikseli.

[self.leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, 10.0, 20.0, 10.0)];    
[self.leftButton setTitleEdgeInsets:UIEdgeInsetsMake(60, -75.0, 0.0, 0.0)];
 0
Author: BADRI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-07 11:16:28

Dokonałem korekty, aby obraz był wyrównany na środku w poziomie:

// 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
Author: Nguyễn Thanh Khiêm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 03:18:53

Czy stosowanie wkładek krawędziowych jest obowiązkowe? Jeśli nie, możesz spróbować ustawić respect w widoku nadrzędnym centrum

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

    }
}
 0
Author: Rodrigo Birriel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-10 15:53:55

Musisz przesunąć obrazek w prawo o szerokość tekstu. Następnie przesuń tekst w lewo o szerokość obrazu.

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;

Następnie dopasuj górne i dolne wkładki, aby dostosować Oś Y. Prawdopodobnie można to zrobić również programowo, ale powinno być stałe dla rozmiaru obrazu. Natomiast wstawki osi X będą musiały się zmieniać w zależności od rozmiaru etykiety tekstowej w każdym przycisku.

 0
Author: pkamb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-26 23:48:16