레이블 너비에 따른 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 2014-07-23

답변:


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 스크린 샷을 만들었습니다. 레티 나가 아닌 디스플레이에서는 선명하지 않지만 문자가 잘린 것을 볼 수 있습니다. 해결 방법에 대한 귀하의 제안은 정말 감사하겠습니다!
pulp

2
sizeToFit 대신 sizeWithAttributes를 사용하여 텍스트의 CGSize를 가져온 다음 레이블의 프레임을 새 크기로 설정합니다.
Basheer_CAD

제안 해 주셔서 감사합니다.하지만 여전히 하단과 끝에 myLabel이 잘려 있습니다. 아마도 당신의 제안을 구현하는 데 잘못되었을 것입니다. 여기 내 코드가 있습니다
pulp

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

49

Swift 4.2 이상

원칙은 다음과 같습니다.

  1. 확인 대표단 (예 : 설정 collectionView.delegate = self)

  2. 구현 UICollectionViewDelegateFlowLayout(필요한 메서드 서명 포함).

  3. 호출 collectionView...sizeForItemAt방법.

  4. 메서드 를 호출 String하기 위해 브리지 캐스팅 할 필요가 없습니다 . Swift 는 즉시 사용할 수 있습니다.NSStringsize(withAttributes: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 객체입니다. 텍스트의 크기 만 필요하기 때문에 오버 헤드 솔루션 이지만 전체 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

빠른 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 19

@Hassan 감사합니다 형제 나를 위해 일했지만 너비에 문제가 있으므로 CGSize (width : label.frame.width + 50, height : 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 귀하의 답변에 감사드립니다. 확실히 확인하고 알려 드리겠습니다!
pulp

+1000 이것은 확실히 작동합니다. 귀하와 Basheer의 게시물에는 함께 녹색 확인 표시가 있어야합니다.
rocky raccoon

신속한 3으로 이것을 수행하는 방법을 아십니까?
UKDataGeek

1
감사합니다, 파티 타임 !!
Ravi

18

Swift 3에서

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

14

스위프트 4

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

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.