iPhone UIButton - görüntü konumu


116

Bir var UIButton"app keşfedin" ve metin ile UIImage(>) olarak Interface Builderbenzediğini:

[ (>) Explore the app ]

Ancak bunu UIImagemetinden SONRA yerleştirmem gerekiyor :

[ Explore the app (>) ]

UIImageSağa nasıl hareket edebilirim ?


Interface Builder'ı da kullanabilirsiniz.
Cevabıma

1
Bu alt sınıfı birkaç satır kodla kullanın: github.com/k06a/RTLButton
k06a

Yanıtlar:


161

Buna çözümüm oldukça basit

[button sizeToFit];
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);

4
Bu harika çalışıyor! Edge inset konseptini anlamak zor. Neden hem sol hem de sağ kenar eklemeyi ayarlamamız gerektiğine dair bir fikriniz var mı? Teorik olarak başlığı sola, resmi sağa kaydırırsam bu yeterli olacaktır. Neden hem sola hem de sağa ayarlamam gerekiyor?
PokerIncome.com


2
Bu cevap mükemmel çalışıyor. Kabul edilen yanıt doğrudur ve doğru API belgelerine işaret etmektedir, ancak bu, OP'nin talep ettiği şeyi yapmak için kopyalayıp yapıştırma çözümüdür.
mclaughlinj

Düğme metnini değiştirmeye başladığınızda biraz karmaşık hale gelir. Alt sınıflı çözüm bu durumda benim için daha iyi çalıştı.
Brad Goss

Bana sol ve sağ taraflara eşit genişlikler uygulamanız gerektiğini gösterdiğin için teşekkür ederim, nasıl çalıştığını% 100 anlamıyorum (çünkü bazen boyutu ve menşei de etkileyecek) ama benzer sorunları çözebildim bu yöntemi kullanarak.
Toby

128

On iOS 9 itibaren, bunu başarmak için basit bir yol görünümünün semantik zorlamak gibi görünüyor.

görüntü açıklamasını buraya girin

Veya programlı olarak şunları kullanarak:

button.semanticContentAttribute = .ForceRightToLeft

4
Cevabınızı (+1) ne kadar beğenmiş olsam da, bunu yapmanın "doğru" yolu olmadığını söylemekten nefret ediyorum, ama en kolaylarından biri bu.
farzadshbfn

@farzadshbfn haklısın. Bu kelimeyi "basit" için değiştirdim, daha tutarlı görünüyor.
Alvivi

@farzadshbfn Neden bunun "doğru" yolu bu olmasın?
Samman Bikram Thapa

3
@SammanBikramThapa IMHO'nun doğru yolu semanticContentAttribute, semanticContentAttributekendisini değiştirmek yerine UIButton'u alt sınıflara ayırmak ve layoutSubviews alt görünümlerini geçersiz kılmak ve mizanpaj mantığımıza saygı duymak olacaktır . (değişen anlamsal yaklaşım, uluslararasılaştırma ile iyi
sonuç vermeyecek

@farzadshbfn tamamen doğru. Bu yanıtın çoğu puanı alması önemli değil, doğru değil - Sağdan sola arayüz için UX'i bozabilir.
Pavel Yakimenko

86

Görüntünüz içinde bileşenleri hareket ettirmek için imageEdgeInsetve öğesini ayarlayın titleEdgeInset. Ayrıca tam boyutlu bu grafikleri kullanarak bir düğme oluşturabilir ve bunu düğme için arka plan görüntüsü olarak kullanabilirsiniz (daha sonra titleEdgeInsetsbaşlığı hareket ettirmek için kullanın ).


8
Bir alt sınıf uygulamaktan çok basit bir şekilde ekleri ayarlamak daha az koddur. Eklerin tüm noktası budur. Alt görünümler için (sizin oluşturmadığınız) kareleri değiştirmek daha çok bir bilgisayar korsanlığı gibi geliyor.
Kim André Sand

6
@kimsnarf, gerçekten mi? Görüntünün boyutunda veya başlığın uzunluğunda küçük bir değişiklik yaptığınızda ekleri değiştirmek çok daha az iş (ve daha az kesmek)?
Kirk Woll

54

Raymond W'nin cevabı burada en iyisidir. Özel layoutSubviews ile alt sınıf UIButton. Yapması son derece basit, işte benim için çalışan bir layoutSubviews uygulaması:

- (void)layoutSubviews
{
    // Allow default layout, then adjust image and label positions
    [super layoutSubviews];

    UIImageView *imageView = [self imageView];
    UILabel *label = [self titleLabel];

    CGRect imageFrame = imageView.frame;
    CGRect labelFrame = label.frame;

    labelFrame.origin.x = imageFrame.origin.x;
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);

    imageView.frame = imageFrame;
    label.frame = labelFrame;
}

2
Bu yol, birçok düğmeyi yönetmeniz gerektiğinde daha iyidir, ancak yalnızca bir düğmeyi değiştirmem gerekiyor :)
Pavel Yakimenko

2
Düğme görüntüsü sıfırsa etiket yanlış yerleştirilir, bunun nedeni büyük olasılıkla UIImageView eklenmemiş olmasıdır (iOS6.0'da test edilmiştir). Yalnızca imageView.image nil değilse kareleri düzenlemeyi düşünmelisiniz.
Scakko

2
Her iki görünümün de merkezde kalması için bu yanıta aşağıdaki iyileştirmeyi öneririm: 'CGFloat cumulativeWidth = CGRectGetWidth (imageFrame) + CGRectGetWidth (labelFrame) + 10; CGFloat extremeWidth = CGRectGetWidth (self.bounds) - cumulativeWidth; labelFrame.origin.x = extremeWidth / 2; imageFrame.origin.x = CGRectGetMaxX (labelFrame) + 10; '
i-konov

Bu benim için iOS 7'de kırılıyor. Başkası var mı?
İOS

1
İOS7'yi hiç desteklemeyin, sorununuz ortadan kalkacak. Zaten onu desteklememelisin.
Gil Kum

30

Alt sınıflandırma UIButtonve geçersiz kılmaya ne dersiniz layoutSubviews?

Ardından self.imageView& konumlarının sonradan işlenmesiself.titleLabel


4
Bu, elle ayarlanmış ekleri kullanarak her şeyi doğru bir şekilde yerleştirmeye çalışmakla ilgili diğer tüm tavsiyelerden (yukarıdaki gibi) çok daha kolaydır.
Steven Kramer

13

Başka bir basit yol (yalnızca iOS 9 DEĞİLDİR), bu iki yöntemi geçersiz kılmak için UIButton'u alt sınıflara ayırmaktır.

override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.titleRectForContentRect(contentRect)
    rect.origin.x = 0
    return rect
}

override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.imageRectForContentRect(contentRect)
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect)
    return rect
}

contentEdgeInsets zaten süper kullanılarak hesaba katılıyor.


Teşekkürler! Çok daha fazla yanıtlardan daha böyle ben bu alt sınıf ve geçersiz kılma layoutSubviews () :)
Joe Susnick

1
Alçakgönüllü görüşüme göre bunu yapmanın en iyi yolu :)
DrPatience

9

Uygulamanız hem "soldan sağa" hem de "sağdan sola" yı destekliyorsa, düğme için "sağdan sola" zorlamak bir seçenek değildir.

Benim için işe yarayan çözüm, Storyboard'daki düğmeye eklenebilen ve kısıtlamalarla iyi çalışan bir alt sınıftır (iOS 11'de test edilmiştir):

class ButtonWithImageAtEnd: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let imageView = imageView, let titleLabel = titleLabel {
            let padding: CGFloat = 15
            imageEdgeInsets = UIEdgeInsets(top: 5, left: titleLabel.frame.size.width+padding, bottom: 5, right: -titleLabel.frame.size.width-padding)
            titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageView.frame.width, bottom: 0, right: imageView.frame.width)
        }

    }

}

Başlık ve resim arasındaki boşluk "dolgu" olacaktır.


Tabii ki .forceRightToLeftbir seçenek! Sadece ters değeri ( .forceLeftToRight) kullanın if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft.
manmal

5

Swift'de:

override func layoutSubviews(){
    super.layoutSubviews()

    let inset: CGFloat = 5

    if var imageFrame = self.imageView?.frame,
       var labelFrame = self.titleLabel?.frame {

       let cumulativeWidth = imageFrame.width + labelFrame.width + inset
       let excessiveWidth = self.bounds.width - cumulativeWidth
       labelFrame.origin.x = excessiveWidth / 2
       imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset

       self.imageView?.frame = imageFrame
       self.titleLabel?.frame = labelFrame  
    }
}

4

Cevabı @split ile inşa etmek ...

Cevap harika, ancak düğmenin önceden ayarlanmış özel görüntü ve başlık kenarı eklerine sahip olabileceği gerçeğini görmezden geliyor (örneğin film şeridinde).

Örneğin, görüntünün kabın üstünden ve altından biraz dolgusu olmasını, ancak yine de görüntüyü düğmenin sağ tarafına taşımasını isteyebilirsiniz.

Konsepti bu yöntemle genişlettim: -

- (void) moveImageToRightSide {
    [self sizeToFit];

    CGFloat titleWidth = self.titleLabel.frame.size.width;
    CGFloat imageWidth = self.imageView.frame.size.width;
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth;
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top,
                                            -imageWidth + self.titleEdgeInsets.left,
                                            self.titleEdgeInsets.bottom,
                                            imageWidth - self.titleEdgeInsets.right);

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top,
                                            titleWidth + self.imageEdgeInsets.left + gapWidth,
                                            self.imageEdgeInsets.bottom,
                                            -titleWidth + self.imageEdgeInsets.right - gapWidth);
}

2
// Get the size of the text and image
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font];
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size];

// You can do this line in the xib too:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2));
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2);

Bu, aşağıdaki gibi sağa hizalı bir düğme oluşturur:

[           button label (>)]

Düğme genişliğini bağlama göre ayarlamaz, bu nedenle etiketin solunda boşluk görünür. Bunu, buttonLabelSize.width ve buttonImageSize.width'den düğmenin çerçeve genişliğini hesaplayarak çözebilirsiniz.


1
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

0

Bu çözüm iOS 7 ve üzeri ile çalışır

Sadece alt sınıf UIButton

@interface UIButton (Image)

- (void)swapTextWithImage;

@end

@implementation UIButton (Image)

- (void)swapTextWithImage {
   const CGFloat kDefaultPadding = 6.0f;
   CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{
                                                               NSFontAttributeName:self.titleLabel.font
                                                               }];

   self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
   self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
}

@end

Kullanım (Sınıfınızda bir yerde):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];

0

Önceki cevapların üzerine inşa etmek. Simge ile düğmenin başlığı arasında bir kenar boşluğu olmasını istiyorsanız, etiketin ve simgenin kendinden boyutlandırılmış düğmelerin sınırları üzerinde kaymasını önlemek için kodun biraz değiştirilmesi gerekir.

let margin = CGFloat(4.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width)
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin)

Son kod satırı, otomatik düzen için özünde içerik boyutu hesaplaması için önemlidir.


0

İşte bunu yapmanın kendi yolum (yaklaşık 10 yıl sonra)

  1. UIButton'dan alt sınıf (Swift çağında yaşadığımız için Button)
  2. Yığın görünümüne bir resim ve bir etiket yerleştirin.
class CustomButton: Button {

    var didLayout: Bool = false // The code must be called only once

    override func layoutSubviews() {
        super.layoutSubviews()
        if !didLayout, let imageView = imageView, let titleLabel = titleLabel {
            didLayout = true
            let stack = UIStackView(arrangedSubviews: [titleLabel, imageView])
            addSubview(stack)
            stack.edgesToSuperview() // I use TinyConstraints library. You could handle the constraints directly
            stack.axis = .horizontal
        }
    }
}

0

Swift'de tek hatlı çözüm:

// iOS 9 and Onwards
button.semanticContentAttribute = .forceRightToLeft

Tüm RTL kullanıcıları için düzeni bozacağı için iyi değildir. Onlar için soldan sağa zorlamanız gerekecek. Buradan başka bir çözüm dene.
Pavel Yakimenko
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.