[ios] 레이블 너비에 따른 UICollectionView의 동적 셀 너비

레이블이 포함 된 재사용 가능한 셀에서 셀을로드하는 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;
}



답변

에서 것은 sizeForItemAtIndexPath텍스트의 크기를 반환

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

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


답변

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 개체를 만드는 데까지 가야합니다. 그리고 그 이유 때문에 더럽습니다.


답변

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


답변

코드 아래에서 확인하면 매우 짧은 CGSize를 제공 ​​할 수 있습니다.

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

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


답변

Swift 3에서

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


답변

스위프트 4

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


답변

//보기 didload에 추가

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