Chiều rộng ô động của UICollectionView tùy thuộc vào chiều rộng nhãn


92

Tôi có một UICollectionView, tải các ô từ ô có thể sử dụng lại, có chứa nhãn. Một mảng cung cấp nội dung cho nhãn đó. Tôi có thể thay đổi kích thước chiều rộng nhãn tùy thuộc vào chiều rộng nội dung một cách dễ dàng với sizeToFit. Nhưng tôi không thể tạo ô để phù hợp với nhãn.

Đây là mã

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

loại vấn đề tương tự ... stackoverflow.com/questions/24915443/… ???
Fattie

Câu trả lời:


83

Trong sizeForItemAtIndexPathtrả lại kích thước của văn bản

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

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

4
Bạn không thể tưởng tượng tôi cảm ơn bạn như thế nào! Điều đó thực sự hiệu quả. Bây giờ tôi chỉ cần giải quyết vấn đề [cell.myLabel sizeToFit], vì nó chỉ xuất hiện ở kích thước đầy đủ sau khi cuộn. Nhưng tôi thậm chí đã không gần với giải pháp của bạn.
bột giấy

cảm ơn bạn đã giúp đỡ nhưng tôi vẫn còn một vấn đề. Khi tôi bỏ ghi chú [cell.myLabel sizeToFit], tôi có các từ bị cắt bớt và các chữ cái bị cắt ở dưới cùng nhưng nó trở nên ổn sau khi tôi cuộn (các từ có kích thước bình thường và các chữ cái nhảy lên một chút). Nếu tôi nhận xét và vô hiệu hóa thông báo [cell.myLabel sizeToFit] (tôi đã quyết định thử với IB và nó hoạt động tốt), tôi có các từ bị cắt ở cuối và cuối. Tôi đã tạo ảnh chụp màn hình goo.gl/HaoqQV Nó không sắc nét lắm trên màn hình không võng mạc nhưng bạn có thể thấy rằng các chữ cái đã bị cắt. Đề xuất của bạn về cách giải quyết sẽ thực sự được đánh giá cao!
bột giấy

2
thay vì sizeToFit, hãy sử dụng sizeWithAttributes để lấy CGSize của văn bản, sau đó đặt khung của nhãn với kích thước mới.
Basheer_CAD

cảm ơn bạn đã gợi ý nhưng tôi vẫn có myLabel bị cắt ở cuối và cuối. Có lẽ tôi sai với việc thực hiện đề xuất của bạn. Đây là mã của tôi
cùi

- (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; }
bột giấy

48

Swift 4.2+

Nguyên tắc là:

  1. Đảm bảo rằng ủy quyền được thiết lập (ví dụ collectionView.delegate = self:)

  2. Thực hiện UICollectionViewDelegateFlowLayout(nó chứa chữ ký phương thức cần thiết).

  3. collectionView...sizeForItemAtPhương thức gọi .

  4. Không cần truyền phương thức Stringtới NSStringđể gọi size(withAttributes:. Swift Stringcó nó ra khỏi hộp.

  5. Các thuộc tính giống nhau mà bạn đặt (NS)AttributedString, tức là họ phông chữ, kích thước, trọng lượng, v.v. Tham số tùy chọn.


Giải pháp mẫu:

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

Nhưng rất có thể bạn sẽ muốn chỉ định các thuộc tính chuỗi cụ thể tương ứng với ô của mình, do đó kết quả cuối cùng sẽ giống như sau:

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

Tại sao bạn KHÔNG NÊN sử dụng UILabel để tính toán kích thước? Đây là giải pháp được đề xuất:

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

Có, bạn nhận được cùng một kết quả. Nó trông đơn giản và có vẻ như là một giải pháp phù hợp. Nhưng nó không phù hợp vì: 1) đắt tiền, 2) chi phí cao và 3) bẩn.

Nó đắt vì UILabel là một đối tượng giao diện người dùng phức tạp, được tạo trên mỗi lần lặp bất cứ khi nào ô của bạn sắp hiển thị mặc dù bạn không cần nó ở đây. Đó là một giải pháp chi phí vì bạn chỉ cần lấy kích thước của một văn bản, nhưng bạn có thể tạo ra một đối tượng toàn bộ giao diện người dùng. Và nó bẩn vì lý do đó.


1
đừng quên đặtcollectionView.delegate == self // or whatever-object-which-do-it
Fitsyu

Câu trả lời chính xác. Mặc dù kích thước tôi nhận được nhỏ hơn một chút so với mức cần thiết, nhưng trên các độ dài khác nhau của dây, tôi quyết định tự mình sửa đổi kích thước một chút. Thêm 5 điểm bổ sung vào chiều rộng đã thực hiện thủ thuật:CGSize(width: title.size(withAttributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]).width + 5, height: 50)
Starsky

37

Tôi đã tìm thấy một thủ thuật nhỏ cho nhanh chóng 4.2

Đối với chiều rộng động & chiều cao cố định:

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

Đối với chiều cao động & chiều rộng cố định:

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
Hãy cẩn thận khi sử dụng cái này. Việc tạo và vẽ một UILabel mới cho mỗi phép tính ô là rất tốn kém.
AnthonyR

cần thêm UICollectionViewDelegateFlowLayout
cristianego

3
Để giải quyết nhận xét về việc tạo ra một nhãn giả là tốn kém, có lẽ bạn chỉ có thể tạo một nhãn giả thay vì nhiều nhãn. Tất cả những gì bạn thực sự muốn từ nó là kích thước văn bản từ các thuộc tính nhãn. Tuy nhiên, vào cuối ngày, nó về cơ bản giống như được tính toán kích thước văn bản thông qua sizeWithAttributes, vì vậy có thể đó là câu trả lời ưa thích.
Stephen Paul

@Hassan Cảm ơn người anh em nó đã làm việc cho tôi, nhưng tôi tìm thấy một vấn đề về chiều rộng nên đã thêm trả về CGSize (width: label.frame.width + 50, height: 32). Sau đó, nó hoạt động, tôi nghĩ câu trả lời này nên nằm trong danh sách hàng đầu.
Arshad Shaik,

27

Kiểm tra mã bên dưới bạn có thể đưa ra kích thước CGS rất ngắn.

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

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

@Vineesh TP Cảm ơn bạn đã phản hồi, tôi chắc chắn sẽ kiểm tra và cho bạn biết!
bột giấy

+1000 Cái này chắc chắn hoạt động. Bài đăng của bạn và Basheer nên có dấu kiểm màu xanh lá cây cùng nhau.
Rock raccoon

Bất kỳ ý tưởng làm thế nào để làm điều này với swift 3?
UKDataGeek

1
Cảm ơn Man, Party Time !!
Ravi

18

Trong Swift 3

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

14

Swift 4

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

0

// thêm vào xem didload

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    layout.estimatedItemSize = CGSizeMake(self.breadScrumbCollectionView.frame.size.width, 30); 
self.breadScrumbCollectionView.collectionViewLayout = layout;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.