다른 장치 방향에서 UICollectionViewCell 크기 변경


100

UICollectionView와 함께 사용하고 있습니다 UICollectionViewFlowLayout.

나는 각 셀의 크기를

collectionView:layout:sizeForItemAtIndexPath:

세로에서 가로로 전환 할 때 셀 사이에 패딩 공간을 남기지 않고 CollectionView의 크기에 완전히 맞도록 각 셀의 크기를 조정하고 싶습니다.

질문 :

1) 회전 이벤트 후 셀 크기를 변경하는 방법은 무엇입니까?

2) 그리고 더 나은 방법은 셀이 항상 화면 전체 크기에 맞는 레이아웃을 만드는 방법입니까?


followben의 대답은 현재 받아 들여지고 있지만 몇 가지 문제가 있습니다. 콘솔 오류가 발생하고 새로운 크기의 애니메이션이 올바르게 발생하지 않습니다. 올바른 구현에 대해서는 내 대답을 참조하십시오.
memmons

@ MichaelG.Emmons : 컬렉션보기가 한 번에 하나의 전체 크기 셀만 표시하는 경우 답변이 더 잘 작동합니다. 이 경우 UIKit이를 sizeForItemAtIndexPath호출하기 전에 쿼리하므로 회전에 대해 불평하는 것이 합리적 didRotateFromInterfaceOrientation입니다. 그러나 화면에 여러 셀이있는 컬렉션 뷰의 경우 회전 전에 레이아웃을 무효화하면 뷰가 회전하기 전에 크기가 눈에 띄게 크게 증가합니다. 이 경우 내 대답이 여전히 가장 정확한 구현이라고 생각합니다.
followben 2014 년

@followben 각각 다른 사용 사례에서 문제가 있다는 데 동의합니다. 이 경우 OP는 I would like to adjust the size of each cell to **completely fit the size of the CollectionView**내 대답에서 제안한 솔루션이 정확히 무엇인지 나타냅니다 . 답변에 내 솔루션을 포함하고 어떤 접근 방식이 어떤 조건에서 가장 잘 작동하는지 기록해두면 나에게 충분할 것입니다.
memmons

답변:


200

1) 여러 레이아웃 개체를 유지하고 교체 할 수 있지만 더 간단한 방법이 있습니다. 다음을 UICollectionViewController하위 클래스에 추가하고 필요에 따라 크기를 조정하십시오.

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{    
    // Adjust cell size for orientation
    if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
        return CGSizeMake(170.f, 170.f);
    }
    return CGSizeMake(192.f, 192.f);
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self.collectionView performBatchUpdates:nil completion:nil];
}

호출 -performBatchUpdates:completion:하면 레이아웃이 무효화되고 애니메이션으로 셀 크기가 조정됩니다 (수행 할 추가 조정이없는 경우 두 블록 매개 변수에 nil을 전달할 수 있습니다).

2)에서 항목 크기를 하드 코딩하는 대신 -collectionView:layout:sizeForItemAtIndexPathcollectionView 경계의 높이 또는 너비를 화면에 맞출 셀 수로 나누십시오. collectionView가 가로로 스크롤되는 경우 높이를 사용하고 세로로 스크롤하는 경우 너비를 사용하십시오.


3
왜 전화하지 [self.collectionView.collectionViewLayout invalidateLayout];않습니까?
user102008

7
@ user102008 호출 invalidateLayout은 올바른 크기로 셀을 다시 그리지 만 -performBatchUpdates:completion:변경 사항에 애니메이션을 적용하여 IMHO가 훨씬 더 멋지게 보입니다.
followben

4
제 경우에는 화면을 스크롤 할 때까지 코드가 collectionviewcell의 크기를 조정하지 않습니다.
newguy 2013-08-06

9
didRotateFromInterfaceOrientationiOS 8에서 지원 중단
János

8
iOS8의에, 나는 전화 드렸습니다 coordinator.animateAlongsideTransition에서 viewWillTransitionToSize, 및 호출 performBatchUpdates의 내 animation블록. 이것은 멋진 애니메이션 효과를줍니다.
Mike Taverne

33

에 의해 추가 애니메이션을 가져 오지 않으려면을 performBatchUpdates:completion:사용 invalidateLayout하여 collectionViewLayout을 강제로 다시로드하십시오.

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

13

두 개의 UICollectionViewFlowLayout을 사용하여 해결했습니다. 하나는 세로 용이고 다른 하나는 가로 용입니다. -viewDidLoad에서 내 collectionView에 동적으로 할당합니다.

self.portraitLayout = [[UICollectionViewFlowLayout alloc] init];
self.landscapeLayout = [[UICollectionViewFlowLayout alloc] init];

UIInterfaceOrientation orientationOnLunch = [[UIApplication sharedApplication] statusBarOrientation];

if (UIInterfaceOrientationIsPortrait(orientationOnLunch)) {
    [self.menuCollectionView setCollectionViewLayout:self.portraitLayout];
} else {
    [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout];
}

그런 다음 단순히 collectionViewFlowLayoutDelgate 메서드를 다음과 같이 수정했습니다.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
    CGSize returnSize = CGSizeZero;

    if (collectionViewLayout == self.portraitLayout) {
        returnSize = CGSizeMake(230.0, 120.0);
    } else {
        returnSize = CGSizeMake(315.0, 120.0);
    }

    return returnSize;
}

마지막으로 회전시 레이아웃에서 다른 레이아웃으로 전환합니다.

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
    if (UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {
        [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout animated:YES];
    } else {
        [self.menuCollectionView setCollectionViewLayout:self.portraitLayout animated:YES];
    }
}

8

컬렉션보기 셀 크기를 설정하는 간단한 방법이 있습니다.

UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout;
layout.itemSize = CGSizeMake(cellSize, cellSize);

그래도 애니메이션 가능한지 확실하지 않습니다.


나는 Hai Feng Kao의 대답과 함께 viewWillLayoutSubviews 내부에서 이것을 사용해야했습니다. stackoverflow.com/a/14776915/2298002
온실

7

Swift : 화면 높이의 n % 인 Collection View Cell

뷰 높이의 특정 비율 인 셀이 필요했고 장치 회전에 따라 크기가 조정되었습니다.

위의 도움으로 여기에 해결책이 있습니다.

override func viewDidLoad() {
    super.viewDidLoad()
    automaticallyAdjustsScrollViewInsets = false
    // if inside nav controller set to true
}

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    collectionViewLayout.invalidateLayout()
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSize(width: 100, height: collectionView.frame.height * 0.9)
}

2

.을 사용하는 경우 흐름 레이아웃 하위 클래스에서 회전하고 조정할 때 뷰 컨트롤러에서 autolayout필요합니다 .invalidate layoutoffset

따라서 뷰 컨트롤러에서-

override func willRotateToInterfaceOrientation(toInterfaceOrientation:     UIInterfaceOrientation, duration: NSTimeInterval) {
    self.galleryCollectionView.collectionViewLayout.invalidateLayout()
}

그리고 당신의 FlowLayout Subclass

override func prepareLayout() {
    if self.collectionView!.indexPathsForVisibleItems().count > 0{
    var currentIndex : CGFloat!
    currentIndex = CGFloat((self.collectionView!.indexPathsForVisibleItems()[0] as! NSIndexPath).row)
    if let currentVal = currentIndex{
        self.collectionView!.contentOffset = CGPointMake(currentIndex * self.collectionView!.frame.width, self.collectionView!.contentOffset.y);
    }   
    }     
}

1
이것은 훌륭하게 작동합니다! willRotateToInterfaceOrientationiOS 8에서는 더 이상 사용되지 않지만 viewWillTransitionToSize이것에 대해서도 잘 작동합니다.
keegan3d 2015 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.