Lebar sel dinamis UICollectionView bergantung pada lebar label

94

Saya memiliki UICollectionView, yang memuat sel dari sel yang dapat digunakan kembali, yang berisi label. Sebuah array menyediakan konten untuk label itu. Saya dapat mengubah ukuran lebar label tergantung pada lebar konten dengan mudah dengan sizeToFit. Tapi saya tidak bisa membuat sel agar sesuai dengan label.

Ini kodenya

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    arrayOfStats =  @[@"time:",@"2",@"items:",@"10",@"difficulty:",@"hard",@"category:",@"main"];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:     (NSInteger)section{
    return [arrayOfStats count];
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{

    return CGSizeMake(??????????);
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{

    return 1;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    Cell *cell = (Cell *) [collectionView dequeueReusableCellWithReuseIdentifier:@"qw" forIndexPath:indexPath];
    cell.myLabel.text = [NSString stringWithFormat:@"%@",[arrayOfStats objectAtIndex:indexPath.item]];
    // make label width depend on text width
    [cell.myLabel sizeToFit];

    //get the width and height of the label (CGSize contains two parameters: width and height)
    CGSize labelSize = cell.myLbale.frame.size;

    NSLog(@"\n width  = %f height = %f", labelSize.width,labelSize.height);

    return cell;
}
bubur
sumber
masalah serupa ... stackoverflow.com/questions/24915443/… ???
Fattie

Jawaban:

85

Sebagai sizeForItemAtIndexPathimbalannya ukuran teks

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{

    return [(NSString*)[arrayOfStats objectAtIndex:indexPath.row] sizeWithAttributes:NULL];
}
Basheer_CAD
sumber
4
Anda tidak bisa membayangkan bagaimana saya berterima kasih! Itu benar-benar berhasil. Sekarang saya hanya perlu menyelesaikan masalah [cell.myLabel sizeToFit], karena hanya muncul dalam ukuran penuh setelah di-scroll. Tetapi saya belum pernah mendekati solusi Anda.
bubur
terima kasih atas bantuan Anda tetapi saya masih memiliki satu masalah. Ketika saya menghapus komentar [cell.myLabel sizeToFit] saya memiliki kata-kata yang terpotong dan huruf-huruf terpotong di bagian bawah tetapi menjadi baik-baik saja setelah saya menggulir (kata-kata memiliki ukuran normal dan huruf-hurufnya melonjak sedikit). Jika saya berkomentar dan menonaktifkan pesan [cell.myLabel sizeToFit] (saya memutuskan untuk bermain-main dengan IB dan berfungsi dengan baik) Saya memiliki kata-kata yang terpotong di bagian akhir dan bawah. Saya membuat tangkapan layar goo.gl/HaoqQV Ini tidak terlalu tajam pada tampilan non-retina tetapi Anda dapat melihat bahwa huruf-huruf telah terpotong. Saran Anda tentang cara menyelesaikannya akan sangat dihargai!
bubur kertas
2
alih-alih sizeToFit, gunakan sizeWithAttributes untuk mendapatkan CGSize teks, lalu setel bingkai label dengan ukuran baru.
Basheer_CAD
terima kasih atas sarannya tetapi saya masih memiliki label myLabel di bagian bawah dan akhir. Mungkin saya salah dengan penerapan saran Anda. Ini kode saya
bubur
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ Cell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"qw" forIndexPath:indexPath]; cell.myLbale.text = [NSString stringWithFormat:@"%@",[arrayOfStats objectAtIndex:indexPath.item]]; CGSize textSize; textSize = [[arrayOfStats objectAtIndex:indexPath.item] sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f]}]; [cell.myLbale sizeThatFits:textSize]; //[cell.myLbale sizeToFit]; return cell; }
pulp
50

Swift 4.2+

Prinsipnya adalah:

  1. Pastikan delegasi disiapkan (mis. collectionView.delegate = self)

  2. Implementasikan UICollectionViewDelegateFlowLayout(ini berisi tanda tangan metode yang diperlukan).

  3. collectionView...sizeForItemAtMetode panggilan .

  4. Tidak perlu menjembatani metode cast Stringto NSStringto call size(withAttributes:. Swift Stringmemilikinya di luar kotak.

  5. Atribut sama dengan yang Anda tetapkan (NS)AttributedString, yaitu jenis font, ukuran, berat, dll. Parameter opsional.


Solusi sampel:

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return "String".size(withAttributes: nil)
    }
}

Tetapi Anda kemungkinan besar ingin menentukan atribut string konkret masing-masing ke sel Anda, maka hasil akhir akan terlihat seperti:

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        // dataArary is the managing array for your UICollectionView.
        let item = dataArray[indexPath.row]
        let itemSize = item.size(withAttributes: [
            NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 14)
        ])
        return itemSize
    }
}

Mengapa Anda TIDAK HARUS menggunakan UILabel untuk menghitung ukuran? Inilah solusi yang disarankan:

let label = UILabel(frame: CGRect.zero)
label.text = textArray[indexPath.item]
label.sizeToFit()

Ya, Anda mendapatkan hasil yang sama. Ini terlihat sederhana dan mungkin tampak sebagai solusi masuk ke. Tapi itu tidak tepat karena: 1) mahal, 2) overhead dan 3) kotor.

Biayanya mahal karena UILabel adalah objek UI yang kompleks, yang dibuat pada setiap iterasi setiap kali sel Anda akan ditampilkan meskipun Anda tidak membutuhkannya di sini. Ini adalah solusi overhead karena Anda hanya perlu mendapatkan ukuran teks, tetapi Anda melangkah lebih jauh untuk membuat objek UI secara keseluruhan. Dan itu kotor karena alasan itu.

Hexfire
sumber
1
jangan lupa untuk mengaturcollectionView.delegate == self // or whatever-object-which-do-it
Fitsyu
Jawaban yang bagus. Meskipun ukuran yang saya dapatkan sedikit lebih kecil dari yang seharusnya, pada panjang string yang berbeda, saya memutuskan untuk mengubah ukurannya sendiri sedikit. Menambahkan 5 poin tambahan pada lebar melakukan trik:CGSize(width: title.size(withAttributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]).width + 5, height: 50)
Starsky
37

Saya telah menemukan trik kecil untuk Swift 4.2

Untuk lebar dinamis & tinggi tetap:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let label = UILabel(frame: CGRect.zero)
        label.text = textArray[indexPath.item]
        label.sizeToFit()
        return CGSize(width: label.frame.width, height: 32)
    }

Untuk tinggi dinamis & lebar tetap:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            let label = UILabel(frame: CGRect.zero)
            label.text = textArray[indexPath.item]
            label.sizeToFit()
            return CGSize(width: 120, height: label.frame.height)
        }
Hassan Izhar
sumber
8
Hati-hati menggunakan ini. Membuat dan menggambar UILabel baru untuk setiap kalkulasi sel sangat mahal.
AnthonyR
perlu menambahkan UICollectionViewDelegateFlowLayout
cristianego
3
Untuk mengatasi komentar tentang mahalnya harga membuat label tiruan, mungkin Anda bisa membuat satu label tiruan alih-alih beberapa. Yang Anda inginkan darinya hanyalah ukuran teks dari atribut label. Pada akhirnya, ini pada dasarnya sama dengan menghitung ukuran teks melalui sizeWithAttributes, jadi mungkin itu adalah jawaban yang lebih disukai.
Stephen Paul
@Hassan Terima kasih bro, ini berhasil untuk saya, tetapi saya menemukan masalah dalam lebar jadi tambahkan kembali CGSize (lebar: label.frame.width + 50, tinggi: 32). Kemudian berhasil, saya pikir jawaban ini harus ada di daftar teratas.
Arshad Shaik
27

Lihat kode di bawah ini yang mungkin Anda berikan CGSize sangat singkat.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{

    NSString *testString = @"SOME TEXT";
    return [testString sizeWithAttributes:NULL];
}
Raza.najam
sumber
@Vineesh TP Terima kasih atas tanggapan Anda, saya pasti akan memeriksanya dan memberi tahu Anda!
bubur
+1000 Yang ini pasti berhasil. Kiriman Anda dan Basheer harus memiliki tanda centang hijau bersamaan.
rakun berbatu
Ada ide bagaimana melakukan ini dengan swift 3?
UKDataGeek
1
Terima Kasih, Waktunya Pestanya !!
Ravi
18

Di Swift 3

let size = (arrayOfStats[indexPath.row] as NSString).size(attributes: nil)
Johnson
sumber
14

Cepat 4

let size = (arrayOfStats[indexPath.row] as NSString).size(withAttributes: nil)
Barath
sumber
0

// tambahkan tampilan didload

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    layout.estimatedItemSize = CGSizeMake(self.breadScrumbCollectionView.frame.size.width, 30); 
self.breadScrumbCollectionView.collectionViewLayout = layout;
Apurva Gaikwad
sumber