ความกว้างของเซลล์แบบไดนามิกของ UICollectionView ขึ้นอยู่กับความกว้างของฉลาก


94

ฉันมี UICollectionView ที่โหลดเซลล์จากเซลล์ที่ใช้ซ้ำได้ซึ่งมีป้ายกำกับ อาร์เรย์จัดเตรียมเนื้อหาสำหรับป้ายกำกับนั้น ฉันสามารถปรับขนาดความกว้างของฉลากขึ้นอยู่กับความกว้างของเนื้อหาได้อย่างง่ายดายด้วย sizeToFit แต่ฉันไม่สามารถสร้างเซลล์ให้พอดีกับฉลากได้

นี่คือรหัส

- (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;
}

ปัญหาที่คล้ายกัน ... stackoverflow.com/questions/24915443/… ???
Fattie

คำตอบ:


85

ในการsizeForItemAtIndexPathส่งคืนขนาดของข้อความ

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

    return [(NSString*)[arrayOfStats objectAtIndex:indexPath.row] sizeWithAttributes:NULL];
}

4
คุณนึกไม่ออกว่าฉันจะขอบคุณอย่างไร! ที่ได้ผลจริง ตอนนี้ฉันต้องการแก้ไขปัญหา [cell.myLabel sizeToFit] เท่านั้นเพราะมันจะปรากฏเป็นขนาดเต็มหลังจากเลื่อนเท่านั้น แต่ฉันไม่ได้ใกล้ชิดกับวิธีแก้ปัญหาของคุณเลย
เยื่อ

ขอบคุณสำหรับความช่วยเหลือ แต่ฉันยังมีปัญหาอยู่ เมื่อฉันยกเลิกการแสดงความคิดเห็น [cell.myLabel sizeToFit] ฉันมีคำที่ถูกตัดทอนและตัวอักษรถูกตัดที่ด้านล่าง แต่มันก็โอเคหลังจากที่ฉันเลื่อน (คำมีขนาดปกติและตัวอักษรกระโดดขึ้นเล็กน้อย) หากฉันแสดงความคิดเห็นและปิดใช้งานข้อความ [cell.myLabel sizeToFit] (ฉันตัดสินใจเล่นกับ IB และมันก็ใช้ได้ดี) ฉันมีคำที่ตัดท้ายและด้านล่าง ฉันถ่ายภาพหน้าจอgoo.gl/HaoqQVมันไม่ค่อยคมชัดบนจอแสดงผลที่ไม่ใช่เรตินา แต่คุณจะเห็นว่าตัวอักษรถูกตัดออก ข้อเสนอแนะของคุณเกี่ยวกับวิธีแก้ปัญหาจะได้รับการชื่นชมอย่างแท้จริง!
เยื่อกระดาษ

2
แทนที่จะเป็น sizeToFit ให้ใช้ sizeWithAttributes เพื่อรับ CGSize ของข้อความจากนั้นตั้งค่ากรอบป้ายกำกับด้วยขนาดใหม่
Basheer_CAD

ขอบคุณสำหรับคำแนะนำ แต่ฉันยังมี myLabel ที่ด้านล่างและด้านท้าย บางทีฉันอาจผิดพลาดกับการใช้คำแนะนำของคุณ นี่คือรหัสของฉัน
เยื่อกระดาษ

- (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; }
เยื่อกระดาษ

50

Swift 4.2+

หลักการคือ:

  1. ตรวจสอบให้แน่ใจว่าได้ตั้งค่าการมอบหมายแล้ว (เช่นcollectionView.delegate = self)

  2. Implement UICollectionViewDelegateFlowLayout(มีลายเซ็นวิธีการที่จำเป็น)

  3. collectionView...sizeForItemAtวิธีการโทร.

  4. ไม่จำเป็นต้องหล่อสะพานStringเพื่อNSStringการเรียกsize(withAttributes:วิธี Swift Stringมีมันออกมาจากกล่อง

  5. แอตทริบิวต์เหมือนกับที่คุณตั้งไว้(NS)AttributedStringเช่นตระกูลฟอนต์ขนาดน้ำหนัก ฯลฯ พารามิเตอร์เสริม


โซลูชันตัวอย่าง:

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

แต่คุณมักจะต้องการระบุแอตทริบิวต์สตริงที่เป็นรูปธรรมตามเซลล์ของคุณดังนั้นผลตอบแทนสุดท้ายจะมีลักษณะดังนี้:

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

ทำไมคุณไม่ควรใช้ UILabel เพื่อคำนวณขนาด นี่คือวิธีแก้ปัญหาที่แนะนำ:

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

ใช่คุณจะได้รับผลลัพธ์เดียวกัน ดูเหมือนง่ายและอาจดูเหมือนเป็นวิธีแก้ปัญหา แต่ไม่เหมาะสมเนื่องจาก: 1) ราคาแพง 2) ค่าใช้จ่ายและ 3) สกปรก

ราคาแพงเพราะ UILabel เป็นออบเจ็กต์ UI ที่ซับซ้อนซึ่งจะถูกสร้างขึ้นในทุกๆการทำซ้ำเมื่อใดก็ตามที่เซลล์ของคุณกำลังจะแสดงแม้ว่าคุณจะไม่ต้องการที่นี่ก็ตาม เป็นวิธีแก้ปัญหาค่าใช้จ่ายเนื่องจากคุณต้องได้ขนาดของข้อความเท่านั้น แต่คุณสามารถสร้างออบเจ็กต์ UI ทั้งหมดได้ และมันสกปรกด้วยเหตุผลนั้น


1
อย่าลืมตั้งcollectionView.delegate == self // or whatever-object-which-do-it
Fitsyu

คำตอบที่ดี แม้ว่าขนาดที่ฉันได้มาจะเล็กกว่าที่จำเป็นเล็กน้อย แต่ด้วยความยาวที่แตกต่างกันของสตริงฉันตัดสินใจที่จะปรับเปลี่ยนขนาดตัวเองเล็กน้อย การเพิ่มคะแนน 5 คะแนนให้กับความกว้างทำได้:CGSize(width: title.size(withAttributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]).width + 5, height: 50)
Starsky

37

ฉันพบเคล็ดลับเล็ก ๆ สำหรับ swift 4.2

สำหรับความกว้างแบบไดนามิกและความสูงคงที่:

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

สำหรับความสูงแบบไดนามิกและความกว้างคงที่:

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

8
ระวังการใช้สิ่งนี้ การสร้างและวาด UILabel ใหม่สำหรับการคำนวณแต่ละเซลล์นั้นมีราคาแพงมาก
AnthonyR

ต้องเพิ่ม UICollectionViewDelegateFlowLayout
cristianego

3
หากต้องการแสดงความคิดเห็นเกี่ยวกับการสร้างฉลากจำลองที่มีราคาแพงคุณอาจสร้างป้ายกำกับจำลองเพียงป้ายเดียวแทนที่จะเป็นหลายป้าย สิ่งที่คุณต้องการจริงๆคือขนาดข้อความจากแอตทริบิวต์ป้ายกำกับ ในตอนท้ายของวันโดยพื้นฐานแล้วจะเหมือนกับการคำนวณขนาดข้อความผ่านsizeWithAttributesดังนั้นอาจเป็นคำตอบที่ต้องการ
Stephen Paul

@ ฮัสซันขอบคุณครับมันใช้งานได้สำหรับฉัน แต่ฉันพบปัญหาในเรื่องความกว้างดังนั้นจึงเพิ่ม CGSize กลับมา (ความกว้าง: label.frame.width + 50, ความสูง: 32) จากนั้นก็ใช้งานได้ฉันคิดว่าคำตอบนี้ควรอยู่ในรายการด้านบน
Arshad Shaik

27

ชำระเงินด้านล่างรหัสคุณอาจให้ CGSize สั้นมาก

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

    NSString *testString = @"SOME TEXT";
    return [testString sizeWithAttributes:NULL];
}

@Vineesh TP ขอบคุณสำหรับคำตอบของคุณฉันจะตรวจสอบและแจ้งให้คุณทราบอย่างแน่นอน!
เยื่อ

+1000 อันนี้ใช้ได้แน่นอน โพสต์ของคุณและ Basheer ควรมีเครื่องหมายถูกสีเขียวร่วมกัน
แรคคูนหิน

มีความคิดอย่างไรกับ swift 3 บ้าง?
UKDataGeek

1
ขอบคุณผู้ชายเวลาปาร์ตี้ !!
ราวี



0

// เพิ่มในการดู didload

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    layout.estimatedItemSize = CGSizeMake(self.breadScrumbCollectionView.frame.size.width, 30); 
self.breadScrumbCollectionView.collectionViewLayout = layout;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.