41

我有一个带有 2 个 CollectionView 控制器的视图控制器。

我希望旋转时只有一个集合视图调整为自定义大小,而另一个保持不变。

我曾尝试使用:

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

然而,这只会改变两个集合视图。我如何让它只针对一个集合?

4

7 回答 7

65

这是我的 2 美分 - 因为您的商品尺寸是静态的,为什么不在 上设置商品尺寸collectionViewLayout

这样做会更快,而不是期望集合视图为每个单元格调用其委托方法。

viewWillLayoutSubviews可用于检测视图控制器上的旋转。 invalidateLayout可以在集合视图布局上使用以强制它再次准备布局,导致它在这种情况下以新尺寸定位元素。

- (void)viewWillLayoutSubviews;
{
    [super viewWillLayoutSubviews];
    UICollectionViewFlowLayout *flowLayout = (id)self.firstCollectionView.collectionViewLayout;

    if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) {
        flowLayout.itemSize = CGSizeMake(170.f, 170.f);
    } else {
        flowLayout.itemSize = CGSizeMake(192.f, 192.f);
    }

    [flowLayout invalidateLayout]; //force the elements to get laid out again with the new size
}

编辑:使用 Swift2.0 示例更新

override func viewWillLayoutSubviews() {
  super.viewWillLayoutSubviews()

  guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
    return
  }

  if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
    flowLayout.itemSize = CGSize(width: 170, height: 170)
  } else {
    flowLayout.itemSize = CGSize(width: 192, height: 192)
  }

  flowLayout.invalidateLayout()
}
于 2013-09-24T18:48:22.700 回答
49

使用iOS 8以来的新 API,我正在使用:

斯威夫特 3:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    updateCollectionViewLayout(with: size)
}

private func updateCollectionViewLayout(with size: CGSize) {
    if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
        layout.itemSize = (size.width < size.height) ? itemSizeForPortraitMode : itemSizeForLandscapeMode
        layout.invalidateLayout()
    }
}

目标-C:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
        [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
        [self updateCollectionViewLayoutWithSize:size];
}

- (void)updateCollectionViewLayoutWithSize:(CGSize)size {
        UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
        layout.itemSize = (size.width < size.height) ? itemSizeForPortraitMode : itemSizeForLandscapeMode;
        [layout invalidateLayout];
}
于 2015-01-20T13:15:16.133 回答
15

验证答案无效

问题- 使viewWillLayoutSubviews()中的布局无效是一项繁重的工作。 viewWillLayoutSubviews()在ViewController被实例化时被多次调用。

我的解决方案 (Swift) - 在UICollectionViewDelegateFlowLayout中嵌入您的尺寸操作。

// Keep a local property that we will always update with the latest 
// view size.
var updatedSize: CGSize!

// Use the UICollectionViewDelegateFlowLayout to set the size of our        
// cells.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    // We will set our updateSize value if it's nil.
    if updateSize == nil {
        // At this point, the correct ViewController frame is set.
        self.updateSize = self.view.frame.size
    }

    // If your collectionView is full screen, you can use the 
    // frame size to judge whether you're in landscape.
    if self.updateSize.width > self.updateSize.height {
        return CGSize(width: 170, 170)
    } else {
        return CGSize(width: 192, 192)
    }
}

// Finally, update the size of the updateSize property, every time 
// viewWillTransitionToSize is called.  Then performBatchUpdates to
// adjust our layout.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    self.updateSize = size
    self.collectionView!.performBatchUpdates(nil, completion: nil)
}
于 2015-12-15T10:57:01.307 回答
3

您可以更改您的 if 语句。您将需要参考集合视图

if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) && collectionView == self.firstCollectionView) {
   return CGSizeMake(170.f, 170.f);
}
于 2013-09-24T18:34:00.760 回答
2

问题是,如何在 sizeForItemAtIndexPath 中分离两个集合视图。为什么不这样呢?

 func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {

    if collectionView == firstCollectionView{

            return CGSize(width: self.frame.width/3, height: 40)
       }


    else if collectionView == secondCollectionView{

        return CGSize(width: self.frame.width, height: self.frame.height-2)
    }

    abort()
}
于 2015-10-11T18:35:38.167 回答
1

我通过检查设备的旋转然后重新加载布局解决了这个问题。检查屏幕尺寸并使用此尺寸显示我的单元格。

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    //get new width of the screen
    screenRect = [[UIScreen mainScreen] bounds];
    screenWidth = screenRect.size.width;

    //if landscape mode
    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
    {
        screenDivide = 5;
    }
    else
    {
        screenDivide = 3;
    }

    //reload the collectionview layout after rotating
    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
    [layout invalidateLayout];
}

然后我像这样定义单元格

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    screenRect = [[UIScreen mainScreen] bounds];
    screenWidth = screenRect.size.width;

    CGSize elementSize = CGSizeMake(screenWidth/screenDivide, 100);
    return elementSize;
}
于 2016-09-15T21:10:22.353 回答
-2

我已经通过检测setBounds:方法中的方向变化来处理这个问题。我们继承UICollectionView并覆盖该setBounds:方法(见下文)。我们根据集合视图的大小flowLayoutForGallerySize创建一个UICollectionViewFlowLayout具有不同间距和 itemSize 的新对象。

- (void)setBounds:(CGRect)bounds
{
    // detect orientation changes and update itemSize in the flow layout
    CGSize oldSize = self.bounds.size;

    [super setBounds:bounds];

    BOOL wasLandscape = (oldSize.width > oldSize.height);
    BOOL nowLandscape = (bounds.size.width > bounds.size.height);

    if (wasLandscape != nowLandscape) {
        // create a new flow layout object for the new gallery size
        self.flowLayout = [self flowLayoutForGallerySize:bounds.size];

        // change to the new flow layout
        [self setCollectionViewLayout:self.flowLayout animated:NO];

        DLog(@"orientation change to %@", NSStringFromCGSize(bounds.size));
    }
}
于 2013-09-24T17:36:01.100 回答