iOS: UILabel Multi-line di Tata Letak Otomatis

183

Saya mengalami kesulitan mencoba mencapai beberapa perilaku tata letak yang sangat mendasar dengan Auto Layout. Pengontrol tampilan saya terlihat seperti ini di IB:

masukkan deskripsi gambar di sini

Label teratas adalah label judul, saya tidak tahu berapa banyak garis itu. Saya perlu label judul untuk menampilkan semua baris teks. Saya juga membutuhkan dua label lainnya dan gambar kecil untuk diletakkan tepat di bawah judul, betapapun tingginya. Saya telah menetapkan batasan jarak vertikal antara label dan gambar kecil, serta batasan jarak atas antara label judul dan superview dan batasan spasi bawah antara gambar kecil dan superview-nya. UIView putih tidak memiliki batasan ketinggian, sehingga harus meregang secara vertikal untuk memuat subview-nya. Saya telah menetapkan jumlah baris untuk label judul menjadi 0.

Bagaimana saya bisa mendapatkan label ukuran untuk menyesuaikan agar sesuai dengan jumlah baris yang dibutuhkan oleh string? Pemahaman saya adalah bahwa saya tidak dapat menggunakan metode setFrame karena saya menggunakan Tata Letak Otomatis. Dan saya harus menggunakan Tata Letak Otomatis karena saya membutuhkan pandangan lain untuk tetap di bawah label judul (karenanya kendala).

Bagaimana saya bisa mewujudkannya?

James Harpe
sumber
3
Saya juga berjuang dengan masalah yang sama. Tapi saya masih berjuang untuk mendapatkan label teratas untuk menyesuaikan ketinggiannya secara dinamis agar sesuai dengan konten. Bagaimana Anda mencapai ini?
jbandi
1
Silakan mempertimbangkan menandai jawaban mwhuss sebagai jawaban yang diterima.
jemmons
1
Apakah Anda mencapai hasil yang diminta?
Aniruddha
periksa ini, Anda tidak perlu menambahkan satu baris kode stackoverflow.com/a/36862795/4910767
Badal Shah

Jawaban:

254

Gunakan -setPreferredMaxLayoutWidthpada UILabeldan autolayout harus menangani sisanya.

[label setPreferredMaxLayoutWidth:200.0];

Lihat dokumentasi UILabel di preferMaxLayoutWidth .

Memperbarui:

Hanya perlu mengatur heightkendala di storyboard Greater than or equal to, tidak perlu setPreferredMaxLayoutWidth.

mwhuss
sumber
8
Bagus, toh melakukan ini di pembuat antarmuka?
Sjoerd Perfors
12
Juga atur batasan ketinggian di IB menjadi Lebih dari atau sama dengan ".
jowie
10
Pengingat: harap ingat untuk mengatur properti numberOfLines.
Li Fumin
2
Yap, gunakan apa pun yang Anda inginkan dengan lebar maksimum.
mwhuss
4
Lihat stackoverflow.com/a/29180323/1529675 untuk mengetahui cara menentukan preferredMaxLayoutWidthdan melihat devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html untuk penulisan singkat namun informatif, lengkap dengan animasi GIF (bukan tulisan saya, saya menemukannya melalui Google)
tboyce12
213

Luaskan label set jumlah garis Anda ke 0 dan juga yang lebih penting untuk tata letak otomatis atur tinggi ke> = x. Tata letak otomatis akan melakukan sisanya. Anda juga dapat memuat elemen lain berdasarkan elemen sebelumnya untuk memposisikannya dengan benar.

tata letak otomatis

Charlie Wu
sumber
Jika metode ini tidak berhasil untuk Anda, silakan lihat jawaban Cory Imdieke tentang memastikan bahwa tampilan selanjutnya tidak melarang Auto Layout mengubah ukuran tampilan (mungkin) multiline.
Tom Howard
1
Ini adalah satu-satunya jawaban yang bekerja untuk saya dalam Table View Cell. Juga bekerja dengan jumlah baris tetap (bukan 0 / tidak terbatas)
bgolson
Ini tidak berfungsi untuk saya dengan set lebar maksimum yang diutamakan eksplisit jadi pastikan ini disetel ke otomatis dalam IB saat menggunakan teknik ini. Cheers
jmc
Pengaturan lebar maks otomatis hanya tersedia di iOS8. Selain itu, dari pemahaman saya, akan menyesuaikan ketinggian secara otomatis dan menurut pengalaman saya, Anda tidak perlu menetapkan batasan ketinggian agar bisa berfungsi. Ini bekerja untuk saya menggunakan lebar eksplisit.
Tony
1
Ini tidak berhasil untuk saya. Saya percaya stackoverflow.com/a/13032251/1529675 adalah jawaban yang benar.
tboyce12
48

Sumber: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

Ukuran Konten Intrinsik dari Teks Multi-Baris

Ukuran konten intrinsik dari UILabel dan NSTextField ambigu untuk teks multi-baris. Ketinggian teks tergantung pada lebar garis, yang belum ditentukan saat menyelesaikan kendala. Untuk mengatasi masalah ini, kedua kelas memiliki properti baru yang disebut preferMaxLayoutWidth, yang menentukan lebar garis maksimum untuk menghitung ukuran konten intrinsik.

Karena kita biasanya tidak mengetahui nilai ini sebelumnya, kita perlu mengambil pendekatan dua langkah untuk mendapatkan ini dengan benar. Pertama kita membiarkan Tata Letak Otomatis melakukan tugasnya, dan kemudian kita menggunakan bingkai yang dihasilkan dalam tata letak lulus untuk memperbarui lebar maksimum yang diinginkan dan memicu tata letak lagi.

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

Panggilan pertama ke [super layoutSubviews] diperlukan untuk label untuk mengatur frame-nya, sementara panggilan kedua diperlukan untuk memperbarui tata letak setelah perubahan. Jika kami mengabaikan panggilan kedua, kami mendapatkan kesalahan NSInternalInconsistencyException, karena kami telah membuat perubahan dalam tata letak pass yang membutuhkan pembaruan kendala, tetapi kami tidak memicu tata letak lagi.

Kita juga bisa melakukan ini di label subclass itu sendiri:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

Dalam hal ini, kita tidak perlu memanggil [super layoutSubviews] terlebih dahulu, karena ketika layoutSubviews dipanggil, kita sudah memiliki bingkai pada label itu sendiri.

Untuk melakukan penyesuaian ini dari level controller tampilan, kami menghubungkan ke viewDidLayoutSubviews. Pada titik ini frame dari lintasan Tata Letak Otomatis pertama telah ditetapkan dan kita dapat menggunakannya untuk mengatur lebar maksimum yang diinginkan.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

Terakhir, pastikan Anda tidak memiliki batasan ketinggian eksplisit pada label yang memiliki prioritas lebih tinggi daripada prioritas resistensi kompresi konten label. Kalau tidak, itu akan mengalahkan tinggi konten yang dihitung. Pastikan untuk memeriksa semua kendala yang dapat memengaruhi ketinggian label.

Anton Matosov
sumber
terima kasih terima kasih terima kasih atas tidak hanya kode, tetapi yang lebih penting penjelasan dan contoh bagaimana melakukan ini tidak hanya di subkelas, tetapi juga dari pengontrol tampilan.
djibouti33
Saya mencoba ini di controller tampilan saya, dan viewDidLayoutSubviews dipanggil setelah viewWillAppear dan viewDidAppear. Setelah viewDidAppear, ada flash ketika label diubah ukurannya dengan benar. Apakah ada cara untuk menghindari hal ini? apakah ada cara untuk mengubah ukuran menjadi lengkap sebelum pengguna melihat sesuatu? dalam kasus saya, label multi-baris saya ada di tableHeaderView, jadi saya juga mengubah ukuran ketinggian tampilan header berdasarkan label menggunakan contoh ini ( stackoverflow.com/questions/20982558/… )
djibouti33
@ djibouti33 dapatkah Anda memberikan kode sampel minimum (misalnya dalam format github repo) sehingga saya dapat dengan mudah memeriksa masalah Anda?
Anton Matosov
Terima kasih @Anton. Desain kami sejak itu telah beralih dari UITableView ke UICollectionView, dan untungnya saya tidak melihat perilaku ini. Jika saya bisa mendapatkan sejarah git saya untuk membuat proyek sampel kecil, saya akan memberi tahu Anda.
djibouti33
Masalah bagi saya sejak saya mulai menjalankan pada iOS 9 sim tetapi ketika saya diuji pada iOS 8 maka masalah dimulai. Saya perlu mengatur lebar maks secara manual.
naz 615
17

Saya hanya bertarung dengan skenario yang tepat ini, tetapi dengan beberapa pandangan lagi yang perlu diubah ukurannya dan bergerak ke bawah sesuai kebutuhan. Itu membuatku gila, tapi aku akhirnya menemukan jawabannya.

Inilah kuncinya: Pembuat Antarmuka suka melempar kendala tambahan saat Anda menambah dan memindahkan tampilan dan Anda mungkin tidak menyadarinya. Dalam kasus saya, saya memiliki pandangan setengah jalan yang memiliki batasan tambahan yang menentukan ukuran antara itu dan superview, pada dasarnya menyematkannya ke titik itu. Itu berarti bahwa tidak ada ukuran di atasnya yang dapat mengubah ukuran lebih besar karena akan bertentangan dengan batasan itu.

Cara mudah untuk mengetahui apakah ini masalahnya adalah dengan mencoba mengubah ukuran label secara manual. Apakah IB membiarkan Anda menanamnya? Jika ya, apakah label di bawah ini bergerak seperti yang Anda harapkan? Pastikan Anda telah memeriksa keduanya sebelum mengubah ukuran untuk melihat bagaimana kendala Anda akan menggerakkan pandangan Anda:

Menu IB

Jika tampilan macet, ikuti pandangan di bawahnya dan pastikan salah satu dari mereka tidak memiliki ruang atas untuk batasan superview. Kemudian pastikan jumlah opsi baris Anda untuk label diatur ke 0 dan harus mengurus sisanya.

Cory Imdieke
sumber
Yap, setelah banyak bermain-main dengannya saya bisa mendapatkan efek yang saya inginkan. Anda hanya harus berpikir dengan sangat hati-hati tentang kendala yang Anda inginkan. Itu tidak membantu bahwa IB terus-menerus melemparkan kendala yang tidak Anda harapkan.
James Harpe
5

Saya menemukan Anda membutuhkan yang berikut:

  • Sebuah kendala utama
  • Kendala utama (mis. Sisi kiri)
  • Batasan trailing (misalnya sisi kanan)
  • Atur prioritas pelukan konten, horizontal ke rendah, sehingga akan mengisi ruang yang diberikan jika teks pendek.
  • Atur resistensi kompresi konten, horizontal ke rendah, jadi itu akan membungkus alih-alih mencoba menjadi lebih luas.
  • Setel jumlah baris ke 0.
  • Atur mode istirahat baris ke bungkus kata.
Chris
sumber
Ini seharusnya bekerja di xcode9. Saya tidak perlu melakukan apa pun dengan batasan ketinggian label (saya tidak punya): itu hanya berfungsi di luar kotak belakangan ini setelah label akan dibatasi (trailing, memimpin, atas dan bawah). uikit mengerjakan sisanya
Anton Tropashko
Prioritas pelukan konten adalah masalah saya. Terima kasih telah membuat saya menyadari properti itu serta ketahanan kompresi. Anda membantu saya menyelesaikan masalah selama berjam-jam.
David Gay
0

Tidak ada solusi berbeda yang ditemukan dalam banyak topik pada subjek yang bekerja dengan baik untuk kasus saya (x label multiline dinamis dalam sel tampilan tabel dinamis).

Saya menemukan cara untuk melakukannya:

Setelah menetapkan batasan pada label Anda dan mengatur properti multiline ke 0, buat subkelas dari UILabel; Saya menelepon milikku AutoLayoutLabel:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end
Tanguy G.
sumber
0

Saya memiliki UITableViewCell yang memiliki label bungkus teks. Saya mengerjakan pembungkus teks sebagai berikut.

1) Tetapkan batasan UILabel sebagai berikut.

masukkan deskripsi gambar di sini

2) Atur no. dari garis ke 0.

3) Menambahkan batasan ketinggian UILabel ke UITableViewCell.

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) Pada UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5
AG
sumber
-12

Salah satu cara untuk melakukan ini ... Ketika panjang teks bertambah, cobalah untuk mengubah (mengurangi) ukuran font dari teks label yang digunakan

Label.adjustsFontSizeToFitWidth = YES;
pengguna1662392
sumber
1
Saya ingin instance berbeda dari view controller memiliki tampilan yang konsisten, jadi saya tidak ingin mengubah ukuran font.
James Harpe