iPhone UIButton - posisi gambar

116

Saya memiliki UIButtonteks dengan teks "Jelajahi aplikasi" dan UIImage(>) Di Interface Builderdalamnya terlihat seperti:

[ (>) Explore the app ]

Tapi saya perlu menempatkan ini UIImageSETELAH teks:

[ Explore the app (>) ]

Bagaimana cara memindahkan UIImageke kanan?

Pavel Yakimenko
sumber
Anda juga dapat menggunakan Interface Builder. Lihat jawaban saya di sini: stackoverflow.com/questions/2765024/…
n8tr
1
Cukup gunakan subclass ini dengan beberapa baris kode: github.com/k06a/RTLButton
k06a

Jawaban:

161

Solusi saya untuk ini cukup sederhana

[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);
Membagi
sumber
4
Ini bekerja dengan baik! Sulit untuk memahami konsep inset tepi. Adakah ide mengapa kita perlu mengatur inset tepi kiri dan kanan? Secara teoritis, jika saya memindahkan judul ke kiri dan gambar ke kanan, itu sudah cukup. Mengapa saya perlu menyetel kiri dan kanan?
PokerIncome.com
3
SOLUSI TERBAIK YANG SAYA DITEMUKAN
Bimawa
2
Jawaban ini bekerja dengan sempurna. Jawaban yang diterima benar, dan menunjuk ke dokumen API yang benar, tetapi ini adalah solusi salin dan tempel untuk melakukan apa yang diminta OP.
mclaughlinj
Menjadi sedikit rumit saat Anda mulai mengubah teks tombol. Solusi subclass bekerja lebih baik untuk saya dalam kasus ini.
Brad Goss
Terima kasih telah menunjukkan kepada saya bahwa Anda harus menerapkan lebar yang sama ke sisi kiri dan kanan, saya tidak 100% mengerti cara kerjanya (karena terkadang itu akan memengaruhi ukuran serta asal) tetapi saya telah dapat menyelesaikan masalah serupa menggunakan metode ini.
Toby
128

Pada iOS 9 dan seterusnya, tampaknya cara sederhana untuk mencapai ini adalah dengan memaksa tampilan semantik.

masukkan deskripsi gambar di sini

Atau secara terprogram, menggunakan:

button.semanticContentAttribute = .ForceRightToLeft
Alvivi
sumber
4
Meskipun saya menyukai jawaban Anda (+1), saya tidak suka mengatakan bahwa ini mungkin bukan cara yang "tepat" untuk melakukan ini, tetapi ini salah satu yang termudah.
farzadshbfn
@rachmandrizal Anda benar. Saya mengubah kata untuk "sederhana", tampaknya lebih konsisten.
Alvivi
@farzadshbfn Mengapa ini bukan cara yang "tepat" untuk dilakukan?
Samman Bikram Thapa
3
@SammanBikramThapa IMHO cara yang tepat adalah dengan subclass UIButton dan menimpa layoutSubviews dan menghormati semanticContentAttributedalam logika tata letak kita, daripada mengubah semanticContentAttributedirinya sendiri. (mengubah pendekatan semantik, tidak akan bekerja dengan baik dengan internasionalisasi)
farzadshbfn
@farzadbbn sepenuhnya benar. Tidak peduli skor jawaban ini kebanyakan poin itu tidak benar - Ini mungkin merusak UX untuk antarmuka kanan ke kiri.
Pavel Yakimenko
86

Atur imageEdgeInsetdan titleEdgeInsetuntuk memindahkan komponen di dalam gambar Anda. Anda juga dapat membuat tombol menggunakan grafik yang berukuran penuh, dan menggunakannya sebagai gambar latar belakang tombol (kemudian digunakan titleEdgeInsetsuntuk memindahkan judul).

Steven Canfield
sumber
8
Ini jauh lebih sedikit kode untuk hanya mengatur insets daripada menerapkan subclass. Ini adalah inti dari insets. Memanipulasi bingkai untuk sub tampilan (yang belum Anda buat) terasa lebih seperti retasan.
Kim André Sand
6
@kimsnarf, benarkah? Jauh lebih sedikit pekerjaan (dan lebih sedikit peretasan) untuk mengubah insets setiap kali Anda membuat perubahan kecil dalam ukuran gambar atau panjang judul?
Kirk Woll
54

Jawaban Raymond W adalah yang terbaik di sini. Subclass UIButton dengan custom layoutSubviews. Sangat mudah dilakukan, berikut adalah implementasi layoutSubviews yang berhasil untuk saya:

- (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;
}
Chris Miles
sumber
2
Cara ini lebih baik jika Anda perlu mengelola banyak tombol, tetapi saya hanya perlu mengubah satu tombol :)
Pavel Yakimenko
2
Jika gambar tombol nihil, hasil label salah tempat, mungkin karena UIImageView tidak dimasukkan (Diuji di iOS6.0). Anda harus mempertimbangkan untuk mengedit bingkai hanya jika imageView.image tidak nihil.
Scakko
2
Saya akan menyarankan perbaikan berikut untuk jawaban ini sehingga kedua pandangan tetap terpusat: 'CGFloat cumulativeWidth = CGRectGetWidth (imageFrame) + CGRectGetWidth (labelFrame) + 10; CGFloat excessWidth = CGRectGetWidth (self.bounds) - cumulativeWidth; labelFrame.origin.x = excessWidth / 2; imageFrame.origin.x = CGRectGetMaxX (labelFrame) + 10; '
i-konov
Ini rusak di iOS 7 untuk saya. Ada lagi? Berfungsi dengan baik di iOS 8.
rounak
1
Jangan mendukung iOS7 sama sekali dan masalah Anda akan hilang. Anda seharusnya tidak mendukungnya.
Gil Sand
30

Bagaimana dengan subclassing UIButtondan overriding layoutSubviews?

Kemudian pasca-pemrosesan lokasi self.imageView&self.titleLabel

Raymond W.
sumber
4
Ini jauh lebih mudah daripada semua saran lainnya (seperti di atas) tentang mencoba menempatkan semuanya dengan benar menggunakan sisipan yang disetel dengan tangan.
Steven Kramer
13

Cara sederhana lainnya (yang BUKAN hanya untuk iOS 9) adalah dengan subclass UIButton untuk mengganti kedua metode ini

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 sudah diperhitungkan dengan menggunakan super.

DrAL3X
sumber
Terima kasih! Saya suka ini lebih dari jawaban yang subclass dan menimpa layoutSubviews () :)
Joe Susnick
1
Cara terbaik untuk melakukan ini menurut pendapat saya :)
DrPatience
9

Memaksakan 'kanan-ke-kiri' untuk tombol bukanlah suatu opsi jika aplikasi Anda mendukung 'kiri-ke-kanan' dan 'kanan-ke-kiri'.

Solusi yang berhasil untuk saya adalah subclass yang dapat ditambahkan ke tombol di Storyboard dan berfungsi dengan baik dengan kendala (diuji di iOS 11):

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

    }

}

Di mana 'padding' adalah ruang antara judul dan gambar.

Luisma
sumber
Tentu saja .forceRightToLeftada pilihan! Cukup gunakan nilai kebalikan ( .forceLeftToRight) jika UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft.
manmal
5

Di Swift:

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  
    }
}
ChikabuZ
sumber
4

Membangun jawaban oleh @split ...

Jawabannya luar biasa, tetapi mengabaikan fakta bahwa tombol tersebut mungkin memiliki gambar kustom dan sisipan tepi judul yang disetel sebelumnya (misalnya di storyboard).

Misalnya, Anda mungkin ingin gambar memiliki bantalan dari atas dan bawah wadah, tetapi tetap memindahkan gambar ke sisi kanan tombol.

Saya memperluas konsep dengan metode ini: -

- (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);
}
BFar
sumber
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);

Ini membuat tombol rata kanan, seperti:

[           button label (>)]

Tombol tidak menyesuaikan lebarnya sesuai dengan konteksnya, sehingga akan muncul spasi di sebelah kiri label. Anda dapat menyelesaikan ini dengan menghitung lebar bingkai tombol dari buttonLabelSize.width dan buttonImageSize.width.

caliss
sumber
1
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
Todd Vanderlin
sumber
0

Solusi ini berfungsi iOS 7 ke atas

Hanya subclass 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

Penggunaan (Di suatu tempat di kelas Anda):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];
Pavel Volobuev
sumber
0

Membangun dari jawaban sebelumnya. Jika Anda ingin memiliki margin antara ikon dan judul tombol, kode harus sedikit berubah untuk mencegah mengambang label dan ikon di atas batas tombol berukuran intrinsik.

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)

Baris kode terakhir penting untuk penghitungan ukuran konten secara intrinsik untuk tata letak otomatis.

Kie
sumber
0

Inilah cara saya sendiri untuk melakukan hal itu, (setelah sekitar 10 tahun)

  1. Subclass dari UIButton (Button, karena kita hidup di era Swift)
  2. Letakkan gambar dan label dalam tampilan tumpukan.
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
        }
    }
}
Pavel Yakimenko
sumber
0

Solusi satu baris di Swift:

// iOS 9 and Onwards
button.semanticContentAttribute = .forceRightToLeft
Sunil Targe
sumber
Ini tidak baik karena akan merusak tata letak untuk semua pengguna RTL. Anda harus memaksa dari kiri ke kanan untuk mereka. Anda lebih baik mencoba solusi lain dari sini.
Pavel Yakimenko