UIButton: imageEdgeInsets ve titleEdgeInsets kullanarak bir görüntü ve metin nasıl ortalanır?


159

Düğmeye yalnızca bir görüntü koyar ve imageEdgeInsets'i en üste daha yakın olarak ayarlarsam, görüntü ortalanır ve tüm beklendiği gibi çalışır:

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

Bir düğmeye yalnızca bir metin koyar ve titleEdgeInsets'i daha dibe yakın ayarlarsam, metin ortalanmış olarak kalır ve tüm beklendiği gibi çalışır:

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

Ancak, 4 satırı bir araya getirirsem, metin görüntüye müdahale eder ve her ikisi de merkez hizalamasını kaybeder.

Tüm resimlerim 30 piksel genişliğe sahip ve setTitleEdgeInsets için UIEdgeInsetMake'in sol parametresine 30 koyarsam, metin tekrar ortalanır. Sorun, resmin button.titleLabel boyutuna bağlı olduğu için asla ortalanmamasıdır. Zaten düğme boyutu, görüntü boyutu, başlık boyutu ile birçok hesaplama denedim ve her ikisi de mükemmel bir şekilde ortalanmıyor.

Birisi zaten aynı problemi yaşadı mı?

Yanıtlar:


412

Değeri için, sihirli sayılar kullanmadan görüntünün metnin üzerinde ortalanması için genel bir çözüm. Aşağıdaki kodun güncel olmadığını ve muhtemelen aşağıdaki güncellenmiş sürümlerden birini kullanmanız gerektiğini unutmayın :

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

Aşağıdaki sürüm, iOS 7+' yi desteklemek için aşağıdaki yorumlarda önerilen değişiklikleri içermektedir . Bu kodu kendim test etmedim, bu yüzden ne kadar iyi çalıştığından veya iOS'un önceki sürümlerinde kullanıldığında kırılıp kırılmayacağından emin değilim.

// 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 5.0 sürümü

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
Harika - teşekkürler! Sanırım başka birçok cevap bu "zor yol" hakkında - bu çok daha iyi görünüyor.
Joe D'Andrea

3
Yukarıdakileri uyandırmak için buldum, ama nasıl yapacağım konusunda kesinlikle hiçbir zihinsel modelim yok. Herkes bireysel EdgeInsets parametrelerinin neler etkilediğine ilişkin resimsel bir açıklama bağlantısı var? Ve metin genişliği neden değişti?
Robert Atkins

3
Görüntü düğmeye sığacak şekilde daraltıldığında bu çalışmaz. UIButton'un (en azından iOS 7'de) merkezleme hesaplamaları için imageView.frame.size değil, image.size kullandığını gösteriyor.
Dan Jackson

5
@ Hemang ve Dan Jackson, önerilerinizi kendim test etmeden birleştiriyorum. Aslında bunu iOS 4 için yazdığım çok saçma buluyorum ve bu birçok sürümden sonra, bu kadar belirgin bir özellik elde etmek için Apple'ın düzen algoritmasını aslında tersine çevirmek zorundayız. Ya da en azından, yukarı yönlü oyların tutarlı akışından ve aşağıdaki eşit derecede acımasız cevaplardan henüz daha iyi bir çözüm olmadığını varsayıyorum (hakaret amaçlı değil).
Jesse Crossen

5
İOS8'de, özellikle düğme metni değişecekse kullanmak button.currentTitleyerine daha iyi buldum button.titleLabel.text. currentTitlehemen yerleştirilirken, titleLabel.textyavaş hizalanmış olabilir, bu da yanlış hizalanmış iç metinlere yol açabilir.
mjangda

59

Nasıl olduğunu buldum.

İlk olarak, metnini yapılandırın titleLabel(stillerden dolayı, örneğin kalın, italik, vb.). Ardından, setTitleEdgeInsetsresminizin genişliğini göz önünde bulundurarak kullanın :

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

Bundan sonra setTitleEdgeInsets, metin sınırlarının genişliğini göz önünde bulundurarak kullanın :

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

Şimdi görüntü ve metin ortalanacaktır (bu örnekte görüntü metnin üstünde görünür).

Şerefe.


3
7 yıl dostum. Gerçekten hatırlamıyorum. Diye sorduğumda kendime cevap verdim Seçilen cevabın yazarı bu sihirli sayıları yok etmeye odaklandığında seçilen cevabı değiştirdim. Böylece, seçilen cevapta, ne anlama geldiğini anlayabilirsiniz.
reinaldoluckman

20

Bunu kısmen Jesse Crossen'in cevabına dayanan bu Swift uzantısı ile yapabilirsiniz:

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

Bu centerLabelVerticallyWithPadding, başlık ve görüntü iç metinlerini uygun şekilde ayarlayan bir işlevi tanımlar .

Ayrıca, intrinsicContentSizeOtomatik Düzen'i kullanması gereken doğru çalışmasını sağlamak için gerekli olduğuna inandığım contentEdgeInsets'i de ayarlar .

UIKit kontrollerini alt sınıfta bulundurmamanız gerektiğinden, UIButton alt sınıfındaki tüm çözümlerin teknik olarak gayri meşru olduğuna inanıyorum. Yani, teoride gelecekteki sürümlerde kırılabilirler.


İOS9'da test etme. Görüntü ortalanmış olarak görünür, ancak metin solda görünür :(
endavid

13

Düzenleme: Swift 3 için güncellendi

Jesse Crossen'in cevabının bir Swift çözümünü arıyorsanız, bunu bir UIButton alt sınıfına ekleyebilirsiniz:

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

Burada bazı harika örnekler var, ama aynı zamanda birden çok metin satırı (metin kaydırma) ile uğraşırken her durumda işe yaramadı. Sonunda işe almak için birkaç tekniği birleştirdim:

  1. Yukarıda Jesse Crossen örneğini kullandım. Ancak, metin yüksekliği sorununu çözdüm ve yatay metin kenar boşluğu belirleme özelliğini ekledim. Kenar boşluğu, metnin kaydırılmasına izin verirken yararlı olur, böylece düğmenin kenarına çarpmaz:

    // 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. Metin etiketini sarmak için ayarladığınızdan emin olun

    button.titleLabel.numberOfLines = 2; 
    button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
    button.titleLabel.textAlignment = UITextAlignmentCenter;
  3. Bu çoğunlukla işe yarayacak. Ancak, resimlerini doğru işlemeyecek bazı düğmelerim vardı. Görüntü sağa veya sola kaydırıldı (ortalanmadı). Bu yüzden imageView'in ortalanmasını zorlamak için bir UIButton düzeni geçersiz kılma tekniği kullandım.

    @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

Bu iyi bir çözüm gibi görünüyor, ancak button.titleLabel.numberOfLines istediği kadar satır olabileceği şekilde 0 olmamalıdır?
Ben Lachman

Benim durumumda en fazla iki satır istedim. Aksi takdirde, görüntünün düğmenin toplam boyutu için sorunlar olur.
Tod Cunningham

9

@ TodCunningham'ın cevabı için bir yöntem yaptım

 -(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

Xcode 11+ için güncellendi

Orijinal yanıtımda açıklanan girişler, Xcode'un daha yeni sürümlerinde boyut denetçisine taşındı. Anahtarın ne zaman gerçekleştiği konusunda% 100 net değilim, ancak öznitelik müfettişinde ek bilgi bulunmuyorsa okuyucular boyut denetçisini incelemelidir. Aşağıda yeni ek ekranın bir örneği verilmiştir (11.5 itibariyle boyut özellikleri denetçisinin üst kısmında bulunur).

insets_moved_to_size_inspector

Orijinal Yanıt

Diğer cevaplar yanlış bir şey yok, ancak ben sadece aynı davranış sıfır kod satırları kullanarak Xcode içinde görsel olarak başarılabilir not etmek istedim. Bu çözüm, hesaplanan bir değere ihtiyacınız yoksa veya bir storyboard / xib ile oluşturuyorsanız yararlıdır (aksi takdirde diğer çözümler geçerlidir).

Not - OP sorusunun kod gerektiren bir soru olduğunu anlıyorum. Bu cevabı tamlık için ve film şeridi / xibs kullananlara mantıklı bir alternatif olarak sunuyorum.

Kenar iç metinleri kullanarak bir düğmenin görüntü, başlık ve içerik görünümlerindeki aralığı değiştirmek için düğmeyi / denetimi seçebilir ve nitelik denetçisini açabilirsiniz. Müfettişin ortasına doğru ilerleyin ve Kenar iç metinleri bölümünü bulun.

kenar ilaveler

Ayrıca başlık, resim veya içerik görünümü için belirli kenar iç metinlerine erişebilir ve bunları değiştirebilirsiniz.

menü seçenekleri


Anlamadığım şey, neden bazı değerler için film şeridine negatif sayılar giremiyorum.
Daniel T.

Bu daha yeni hızlı sürüm için işe yarıyor mu? Edge özelliğini hiçbir yerde bulamıyorum
brockhampton

@brockhampton - yeni konum için güncellenmiş cevaba bakın
Tommie C.

6

Sistemle savaşmayın. Mizanpajlarınız Interface Builder + belki de bazı basit yapılandırma kodlarını kullanarak yönetmek için çok karmaşık hale gelirse, mizanpajları kullanarak daha basit bir şekilde manuel olarak yapın layoutSubviews- işte budur! Diğer her şey hack olacak.

Bir UIButton alt sınıfı oluşturun ve layoutSubviewsmetninizi ve resminizi programlı olarak hizalamak için yöntemini geçersiz kılın . Veya https://github.com/nickpaulson/BlockKit/blob/master/Source/UIView-BKAdditions.h gibi bir şey kullanın, böylece bir blok kullanarak layoutSubviews uygulayabilirsiniz.


6

Alt sınıf 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);
}

6

Swift 4 için Jesse Crossen'in cevabı güncellendi :

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 şekilde kullanın:

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

Çok, çok saat sonra. Bu işe
Harry Blue

4

Bu kod yığınıyla, böyle bir şey alacaksınız başlık ve resim hizalama

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
Resim ve metni düğmenin içine yerleştirmek için küçük bir uzantı yazdım. Eğer ilgileniyorsanız, işte kaynak kodu. github.com/sssbohdan/ButtonAlignmentExtension/blob/master/…
Bohdan Savych

4

Swift 3+ sözdizimi ile UIButton uzantısı :

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

Orijinal cevap: https://stackoverflow.com/a/7199529/3659227


3

Jesse Crossen'in cevabında benim için mükemmel bir şekilde çalışmasını sağlayan küçük bir değişiklik:

onun yerine:

CGSize titleSize = button.titleLabel.frame.size;

Bunu kullandım:

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

SO hoş geldiniz! Ayrı bir cevap eklemek yerine (küçük bir değişiklik için) bunu doğrudan Jesse'ye yazabilirsiniz, böylece [kabul edilen] cevabını doğru bir şekilde kontrol edebilir ve güncelleyebilir (gerekirse).
Hemang

3

Kullanımı button.titleLabel.frame.size.widthgayet sadece sürece etiketi eserler değil kesilmiş gibi kısa yeterlidir. Etiket metni kesildiğinde konumlandırma çalışmaz. alma

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

etiket metni kesilmiş olsa bile benim için çalışır.


botton yazım hatası var.
Bhimbim

2

Mevcut cevaplara baktım ama düğme çerçevesini ayarlamanın önemli bir ilk adım olduğunu gördüm.

İşte bununla ilgilenen bir fonksiyon:

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

Veya bu kategoriyi kullanabilirsiniz:

@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
Bu, özel yazı tipi ile çalışmaz. İOS7 + 'danCGSize titleSize = [button.titleLabel.text sizeWithAttributes: @{NSFontAttributeName: button.titleLabel.font}];
Hemang

1

Kullanım durumum ekleri yönetilemez hale getirdi:

  1. düğmedeki arka plan resmi tutarlı
  2. dize uzunluğunun ve resim boyutunun değiştiği yerde dinamik metin ve resim değişiklikleri

Sonunda bunu yaptım ve bundan oldukça memnunum:

  • Film şeridi üzerinde bir arka plan görüntüsü (bulanıklık ve renk içeren yuvarlak daire) ile düğme oluşturun.

  • Sınıfımda bir UIImageView bildirin:

    @implementation BlahViewController {
        UIImageView *_imageView;
    }
  • İnit'te resim görünümü örneği oluştur:

    -(id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            _imageView = [[UIImageView alloc] initWithCoder:aDecoder];
         }
         return self;
     }
  • ViewDidLoad uygulamasında, resim görünümümüz için düğmeye yeni bir katman ekleyin ve metin hizalamasını ayarlayın:

    [self.btn addSubview:_imageView];
    [self.btn.titleLabel setTextAlignment:NSTextAlignmentCenter];
  • Düğme tıklama yönteminde, seçili bindirme görüntüyü görüntü görünümüne ekleyin, görüntüye sığacak şekilde boyutlandırın ve düğmeye ortalayın, ancak metni yukarı kaydırın, böylece metnin altına kaydırın:

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

Not: ceilf (), görüntü kalitesi için piksel sınırında olduğundan emin olmak için önemlidir.


1
Düğmeyi yığın görünümüne eklediğimden, kullanım durumum için kesinlikle daha iyi bir yaklaşım.
valeCocoa

0

Hem metnin hem de görüntünün yatay olarak ortalanmasını istediğinizi varsayarsak, metnin üstündeki görüntü: Metni arayüz oluşturucudan ortalayın ve bir üst metin ekleyin (görüntü için yer açın). (soldaki metni 0'a bırakın). Görüntüyü seçmek için arayüz oluşturucuyu kullanın - gerçek konumu koddan ayarlanır, bu yüzden IB'de işlerin iyi görünmeyeceğinden endişelenmeyin. Yukarıdaki diğer yanıtların aksine, bu aslında şu anda desteklenen tüm ios sürümlerinde (5,6 ve 7) çalışır.

Kodda, görüntüyü yakaladıktan sonra düğmenin ImageView öğesini (düğmenin görüntüsünü null olarak ayarlayarak) atın (gerekirse, metni otomatik olarak ortalar, gerekirse sarılır). Ardından, kendi ImageView'inizi aynı kare boyutunda ve görüntüsüyle başlatın ve ortaya yerleştirin.

Bu şekilde, görüntüyü arayüz oluşturucusundan seçebilirsiniz (ancak simülatördeki gibi IB'de hizalanmayacak, ancak daha sonra, diğer çözümler desteklenen tüm ios sürümlerinde uyumlu değildir)


0

Bunu yapmak için uğraşıyordum çünkü görüşümün yapıcısında görüntü boyutu ve metin genişliği elde edemedim. Jesse'nin cevabındaki iki küçük değişiklik benim için çalıştı:

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

Değişiklik:

  • kullanma [NSString sizeWithAttributes]Metin genişliği almak için ;
  • Görüntü boyutunu doğrudan UIImageyerine alınUIImageView

0

Bu, benim için, farklı görüntü genişliği ve farklı başlık uzunluğuna sahip birkaç düğme için iyi çalışır:

Alt sınıf 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

Düğme boyutu 80x80 piksel için iyi çalışıyor.

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

0

Görüntüyü merkezde yatay hizalamak için bazı ayarlamalar yaptım:

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

kenar iç metinleri kullanmak zorunlu mu? Değilse, orta üst görünüme saygı göstermeyi deneyebilirsiniz

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

    }
}

Soru açıkça imageEdgeInsets ve titleEdgeInsets kullanımını istiyor, bu yüzden zorunlu olması muhtemel
Tibrogargan

0

Görüntüyü metnin genişliğine göre sağa taşımanız gerekir. Ardından metni görüntünün genişliğine göre sola taşıyın.

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;

Ardından, Y eksenini ayarlamak için üst ve alt girişleri ayarlayın. Bu muhtemelen programlı olarak da yapılabilir, ancak görüntü boyutunuz için sabit olmalıdır. Oysa X ekseni iç metinlerinin her düğmedeki metin etiketinin boyutuna göre değişmesi gerekecektir.


0

Bu kodu Swift 4.2 uzantısına ekleyin

 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

Sadece 2 sentimi atmak, bu benim için çalıştı:

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)
  }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.