如何在旋转时定义CollectionView的大小

时间:2013-09-24 17:17:56

标签: ios objective-c xcode uicollectionview

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

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

我试过用:

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

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

7 个答案:

答案 0 :(得分: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()
}

答案 1 :(得分: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];
}

答案 2 :(得分:14)

已验证的答案效率不高

问题 - 在 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)
}

答案 3 :(得分:3)

您可以更改if语句。您需要引用集合视图

if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) && collectionView == self.firstCollectionView) {
   return CGSizeMake(170.f, 170.f);
}

答案 4 :(得分: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()
}

答案 5 :(得分: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;
}

答案 6 :(得分:-2)

我通过检测setBounds:方法中的方向更改来处理此问题。我们将UICollectionView子类化并覆盖setBounds:方法(见下文)。在flowLayoutForGallerySize中,我们根据集合视图的大小创建一个具有不同间距和itemSize的新UICollectionViewFlowLayout

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