iOS: UIButton mengubah ukuran menurut panjang teks

134

Di pembangun antarmuka, menahan Command+ =akan mengubah ukuran tombol agar sesuai dengan teksnya. Saya bertanya-tanya apakah ini mungkin dilakukan secara pemrograman sebelum tombol ditambahkan ke tampilan.

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button.titleLabel setFont:[UIFont fontWithName:@"Arial-BoldMT" size:12]];
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
// I need to know the width needed to accomodate NSStringVariable
[button setTitle:NSStringVariable forState:UIControlStateNormal]; 
// So that I can set the width property of the button before addSubview
[button setFrame:CGRectMake(10, 0, width, fixedHeight)];
[subNavigation addSubview:button];
Oh Danny Boy
sumber
1
Catatan untuk pertanyaan yang sangat lama ini : saat ini (2017), tetapkan saja batasannya sebagai "lebih besar atau sama" dan itu semua. (Perhatikan jawaban di bawah oleh Tad.)
Fattie
@Fattie Batasan " lebih dari atau sama " tidak cukup untuk kompatibilitas dengan AutoLayout. Saat ini (2017+) seseorang harus membungkus tombol di dalam sesuatu yang mengubah ukuran dengan benar (Bartłomiej Semańczyk menjawab), atau seseorang harus membuat subclass UIButton, seperti di stackoverflow.com/a/50575588/1033581
Cœur
hi @ Cœur - ada banyak kehalusan untuk autolayout. Mungkinkah Anda memikirkan situasi yang sedikit berbeda? Namun, untungnya, Anda benar-benar salah - coba saja !! Cukup letakkan UIButton pada pengontrol tampilan. jelas mengatur pusat horizontal dan vertikal. Dan kemudian tambahkan batasan => 100 lebar. ini bekerja dengan sempurna di iOS terbaru.
Fattie
1
(Bagi siapa pun yang baru melakukan googling autolayout di sini ........... hanya TBC Anda tidak perlu menambahkan apa pun, dan UIButton (juga UILabel, dll.) Akan mengubah ukuran menjadi lebar secara otomatis dengan perubahan teks.
Kendalikan
Demonstrasi @Fattie . Secara khusus, pada saat runtime, ia berperilaku seperti itu: github.com/Coeur/autolayoutButton/blob/master/buttonSelfSizing/…
Cœur

Jawaban:

1

Dalam Xcode 4.5 dan di atas, ini sekarang dapat dilakukan dengan menggunakan ' Auto-layouting / Constraints '.

Keuntungan utama adalah:

  1. Anda tidak perlu mengatur bingkai sama sekali secara terprogram!
  2. Jika dilakukan dengan benar, Anda tidak perlu repot mengatur ulang frame untuk perubahan orientasi.
  3. Juga, perubahan perangkat tidak perlu mengganggu Anda (baca, tidak perlu kode secara terpisah untuk ukuran layar yang berbeda).

Beberapa kelemahan:

  1. Tidak kompatibel ke belakang - hanya berfungsi untuk iOS 6 ke atas.
  2. Perlu dibiasakan (tetapi akan menghemat waktu di kemudian hari).

Yang paling keren adalah kita harus fokus pada menyatakan maksud seperti:

  • Saya ingin dua tombol ini memiliki lebar yang sama; atau
  • Saya ingin tampilan ini dipusatkan secara vertikal dan diperluas hingga 10 poin dari tepi superview; atau bahkan,
  • Saya ingin tombol / label ini diubah ukurannya sesuai dengan label yang ditampilkan!

Berikut ini adalah tutorial sederhana untuk diperkenalkan ke tata-letak otomatis.

Untuk lebih jelasnya .

Awalnya memang butuh waktu, tapi sepertinya akan sepadan dengan usahanya.

codeburn
sumber
3
Saya hampir melewatkan jawaban ini - itu benar-benar membutuhkan lebih banyak suara. Dengan solusi ini, seseorang dapat menghindari menyematkan nama dan ukuran font atau panggilan khusus iOS 7. Saya hanya mengatur batasan sisi yang saya inginkan UIButton saya diperluas dan hanya itu.
Carl
Hampir merupakan solusi yang sempurna, sayangnya itu tidak berfungsi jika Anda menggunakan titleEdgeInsets: /
Zoltán
130
Ini adalah jawaban yang buruk - ini merinci manfaat AutoLayout itu sendiri, daripada bagaimana AutoLayout dapat diterapkan dalam situasi ini untuk menyelesaikan masalah penanya.
mattsven
4
Saya bertanya-tanya apakah ini mungkin dilakukan secara program, mengatakan jawabannya ...
Juan Boero
Batasan Auto Layout @JuanPabloBoeroAlvarez dapat ditentukan dalam Interface Builder dan / atau secara terprogram.
Slipp D. Thompson
130

Dalam UIKit, ada tambahan untuk kelas NSString untuk mendapatkan dari objek NSString yang diberikan ukurannya akan mengambil ketika dirender dalam font tertentu.

Documents ada di sini . Sekarang di sini di bawah usang.

Singkatnya, jika Anda pergi:

CGSize stringsize = [myString sizeWithFont:[UIFont systemFontOfSize:14]]; 
//or whatever font you're using
[button setFrame:CGRectMake(10,0,stringsize.width, stringsize.height)];

... Anda harus mengatur bingkai tombol dengan tinggi dan lebar string yang Anda render.

Anda mungkin ingin bereksperimen dengan beberapa ruang penyangga di sekitar CGSize itu, tetapi Anda akan mulai di tempat yang tepat.

Dan Ray
sumber
4
Sepertinya padding default iOS adalah 12px, 8px.
Ben Lachman
19
sizeWithFont tidak digunakan lagi di iOS 7.0. Gunakan sizeWithAttributes: sebaliknya
carmen_munich
6
Saya sangat menyarankan tidak bermain dengan frame lagi, tetapi HANYA dengan kendala saja.
Gil Sand
@GilSand Apakah ada cara untuk menggunakan pembangun antarmuka untuk ini?
huggie
Ya, pencarian google akan memberi Anda banyak hasil yang bermanfaat
Gil Sand
101

Cara melakukannya dalam kode adalah:

[button sizeToFit];

Jika Anda subklas dan ingin menambahkan aturan tambahan, Anda dapat mengganti:

- (CGSize)sizeThatFits:(CGSize)size;
Daniel Wood
sumber
5
sizeToFit berfungsi dengan baik pada kontrol standar seperti UIButton atau UILabel. Jika Anda melakukannya pada UIView khusus, Anda harus menerapkannya -(CGSize)sizeThatFits:(CGSize)size.
Cameron Lowell Palmer
4
Ini hanya berfungsi jika Anda meletakkannya setelah mengatur teks, jika tidak, tidak ada informasi yang cukup tentang seberapa besar seharusnya: [button setTitle:@"Your text here" forState:UIControlStateNormal]; [button sizeToFit]; Juga jika Anda memperbarui teks nanti, jangan lupa menyebutnya lagi.
Juan Boero
Pastikan Anda hanya mengatur teks seperti itu: [myButton setTitle: @ "my title" forState: UIControlStateNormal]; Bagi saya itu tidak berhasil sampai saya mengulangi pernyataan itu.
Darius Miliauskas
7
sizeToFit()tidak menghormati insets judul tepi.
kelin
32

Jika tombol Anda dibuat dengan Interface Builder, dan Anda mengubah judul dalam kode, Anda dapat melakukan ini:

[self.button setTitle:@"Button Title" forState:UIControlStateNormal];
[self.button sizeToFit];
guptron
sumber
1
Dan Anda dapat melakukannya bahkan jika tombol Anda dibuat dengan kode.
Markus
22

Cepat:

Yang penting di sini adalah kapan Anda akan memanggil .sizeToFit(), itu harus setelah pengaturan teks untuk ditampilkan sehingga dapat membaca ukuran yang dibutuhkan, jika Anda kemudian memperbarui teks, kemudian memanggilnya lagi.

var button = UIButton()
button.setTitle("Length of this text determines size", forState: UIControlState.Normal)
button.sizeToFit()
self.view.addSubview(button)
Juan Boero
sumber
18

Untuk mencapai ini menggunakan autolayout, coba atur batasan lebar variabel:

Kendala Lebar

Anda mungkin juga perlu menyesuaikan Content Hugging Prioritydan Content Compression Resistance Priorityuntuk mendapatkan hasil yang Anda butuhkan.


UILabel sepenuhnya otomatis berukuran sendiri :

UILabel ini hanya diatur untuk dipusatkan di layar (hanya dua kendala, horizontal / vertikal):

Ini mengubah lebar total secara otomatis:

Anda tidak perlu mengatur lebar atau tinggi apa pun - ini sepenuhnya otomatis.

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Perhatikan kotak kuning kecil hanya terpasang ("jarak" dari nol). Mereka secara otomatis bergerak sesuai ukuran UILabel.

Menambahkan batasan "> =" menetapkan lebar minimum untuk label UIL:

masukkan deskripsi gambar di sini

Tad
sumber
16

Jika Anda ingin mengubah ukuran teks sebagai lawan dari tombol, Anda dapat menggunakan ...

button.titleLabel.adjustsFontSizeToFitWidth = YES;
button.titleLabel.minimumScaleFactor = .5;
// The .5 value means that I will let it go down to half the original font size 
// before the texts gets truncated

// note, if using anything pre ios6, you would use I think
button.titleLabel.minimumFontSize = 8;
Logan
sumber
3
* adjustsFontSizeToFitWidth
Daniel Bang
8

sizeToFit tidak berfungsi dengan benar. sebagai gantinya:

myButton.size = myButton.sizeThatFits(CGSize.zero)

Anda juga dapat menambahkan contentInsetke tombol:

myButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 4, 8)

Hashem Aboonajmi
sumber
Dari dokumen Apple tentang sizeToFit: // panggilan sizeThatFits: dengan batas tampilan saat ini dan perubahan ukuran batas. Jadi itu berfungsi dengan benar Anda hanya perlu mengaturnya setelah Anda mengatur teks.
Markus
5

Secara sederhana:

  1. Membuat UIView sebagai pembungkus dengan tata letak otomatis untuk dilihat sekitar.
  2. Taruh UILabel dalam bungkus itu. Tambahkan batasan yang akan menempel label Anda ke tepi bungkus.
  3. Masukkan ke UIButtondalam bungkus Anda, lalu tambahkan batasan yang sama seperti yang Anda lakukan sebelumnyaUILabel .
  4. Nikmati tombol otomatis Anda bersama dengan teks.
Bartłomiej Semańczyk
sumber
1
Apakah ini cocok dengan aksesibilitas?
jasonzhao
4

Cepat 4.2

Terima kasih Tuhan, ini terpecahkan. Setelah mengatur teks ke tombol, Anda dapat mengambil intrinsicContentSize yang merupakan ukuran alami dari UIView (dokumen resmi ada di sini ). Untuk UIButton, Anda dapat menggunakannya seperti di bawah ini.

button.intrinsicContentSize.width

Untuk informasi Anda, saya menyesuaikan lebarnya agar terlihat dengan benar.

button.frame = CGRect(fx: xOffset, y: 0.0, width: button.intrinsicContentSize.width + 18, height: 40)

Simulator

UIButtons dengan intrinsicContentSize

Sumber: https://riptutorial.com/ios/example/16418/get-uibutton-s-size-strictly-based-on-its-text-and-font

nator333
sumber
1
Bisakah Anda memberi sedikit lebih banyak konteks? Bagaimana hubungan kode Anda dengan kode dalam pertanyaan? Bisakah Anda juga merangkum apa yang kode Anda sarankan? Hanya memberikan tautan sebagai penjelasan bukanlah format yang tepat untuk situs ini (lihat meta.stackexchange.com/a/8259/266197 untuk alasan), tetapi jika Anda ingin menambahkan beberapa penjelasan dan konteks, jawaban Anda akan menjadi lebih berharga!
Nih
3

Saya memiliki beberapa kebutuhan tambahan terkait posting ini yang sizeToFittidak menyelesaikannya. Saya perlu menjaga tombol terpusat di lokasi aslinya, terlepas dari teks. Saya juga tidak pernah ingin tombolnya lebih besar dari ukuran aslinya.

Jadi, saya tata letak tombol untuk ukuran maksimumnya, simpan ukuran itu di Controller dan gunakan metode berikut untuk mengukur tombol ketika teks berubah:

+ (void) sizeButtonToText:(UIButton *)button availableSize:(CGSize)availableSize padding:(UIEdgeInsets)padding {    

     CGRect boundsForText = button.frame;

    // Measures string
    CGSize stringSize = [button.titleLabel.text sizeWithFont:button.titleLabel.font];
    stringSize.width = MIN(stringSize.width + padding.left + padding.right, availableSize.width);

    // Center's location of button
    boundsForText.origin.x += (boundsForText.size.width - stringSize.width) / 2;
    boundsForText.size.width = stringSize.width;
    [button setFrame:boundsForText];
 }
raider33
sumber
1

Kelas tombol ini dengan pengatur ketinggian untuk teks (untuk Xamarin tetapi dapat ditulis ulang untuk bahasa lain)

[Register(nameof(ResizableButton))]
public class ResizableButton : UIButton
{
    NSLayoutConstraint _heightConstraint;
    public bool NeedsUpdateHeightConstraint { get; private set; } = true;

    public ResizableButton(){}

    public ResizableButton(UIButtonType type) : base(type){}

    public ResizableButton(NSCoder coder) : base(coder){}

    public ResizableButton(CGRect frame) : base(frame){}

    protected ResizableButton(NSObjectFlag t) : base(t){}

    protected internal ResizableButton(IntPtr handle) : base(handle){}

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();
        UpdateHeightConstraint();
        InvalidateIntrinsicContentSize();
    }

    public override void SetTitle(string title, UIControlState forState)
    {
        NeedsUpdateHeightConstraint = true;
        base.SetTitle(title, forState);
    }

    private void UpdateHeightConstraint()
    {
        if (!NeedsUpdateHeightConstraint)
            return;
        NeedsUpdateHeightConstraint = false;
        var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));

        var rect = new CGRect(Frame.X, Frame.Y, Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);

        if (_heightConstraint != null)
            RemoveConstraint(_heightConstraint);

        _heightConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, rect.Height);
        AddConstraint(_heightConstraint);
    }

     public override CGSize IntrinsicContentSize
     {
         get
         {
             var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));
             return new CGSize(Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);
         }
     }
}
Elamaunt
sumber
1

Untuk beberapa alasan, func sizeToFit()tidak berhasil untuk saya. Pengaturan saya adalah saya menggunakan tombol di dalam aUITableViewCell dan saya menggunakan tata letak otomatis.

Apa yang berhasil untuk saya adalah:

  1. dapatkan batasan lebar
  2. dapatkan intrinsicContentSizelebar karena menurut dokumen ini tata letak otomatis tidak mengetahui intrinsicContentSize. Atur batasan lebar ke intrinsicContentSizelebar

masukkan deskripsi gambar di sini

Inilah dua judul dari Debug View Hierachry masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Loozie
sumber
0

Sejujurnya saya pikir itu sangat memalukan bahwa tidak ada kotak centang sederhana di storyboard untuk mengatakan bahwa Anda ingin mengubah ukuran tombol untuk mengakomodasi teks. Yah ... terserahlah.

Berikut adalah solusi paling sederhana menggunakan storyboard.

  1. Tempatkan UIView dan berikan batasan untuk itu. Contoh: masukkan deskripsi gambar di sini
  2. Tempatkan UILabel di dalam UIView. Tetapkan batasan untuk melampirkannya ke tepi UIView.

  3. Tempatkan UIButton Anda di dalam UIView. Atur batasan yang sama untuk melampirkannya ke tepi UIView.

  4. Set 0 untuk jumlah baris UILabel. masukkan deskripsi gambar di sini

  5. Siapkan gerai.

    @IBOutlet var button: UIButton!
    @IBOutlet var textOnTheButton: UILabel!
  1. Dapatkan beberapa judul yang sangat panjang.

    let someTitle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
  1. Pada viewDidLoad atur judul untuk UILabel dan UIButton.

    override func viewDidLoad() {
        super.viewDidLoad()
        textOnTheButton.text = someTitle
        button.setTitle(someTitle, for: .normal)
        button.titleLabel?.numberOfLines = 0
    }
  1. Jalankan untuk memastikan bahwa tombol diubah ukurannya dan dapat ditekan.

masukkan deskripsi gambar di sini

Shalugin
sumber