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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18988028/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:38:54  来源:igfitidea点击:

How do I define the size of a CollectionView on rotate

iosobjective-cxcodeuicollectionview

提问by Robert Farr

I have a viewcontroller with 2 CollectionView Controllers.

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

I would like on rotation that only one of the collection views resize to a custom size while the other remains the same.

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

I have tried to use:

我曾尝试使用:

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

However that just changes both collectionviews. How do I get it to be specific to only one collection?

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

回答by Oliver Atkinson

Heres my 2 cents - because your item sizes are static why don't you set the item size on the collectionViewLayout?

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

It will be quicker to do this rather than expecting the collection view to call its delegate method for every cell.

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

viewWillLayoutSubviewscan be used for detection of rotation on view controllers. invalidateLayoutcan be used on a collection view layout to force it to prepare the layout again causing it to position the elements with the new sizes in this case.

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
}

edit: updated with Swift2.0 example

编辑:使用 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()
}

回答by Tomasz B?k

With new API since iOS 8I'm using:

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

Swift 3:

斯威夫特 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()
    }
}

Objective-C:

目标-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];
}

回答by Neil Japhtha

The Verified Answer Is Not Efficient

经验证的答案无效

The Problem- Invalidating the layout in viewWillLayoutSubviews()is heavy work. viewWillLayoutSubviews()gets called multiple times when a ViewControlleris instantiated.

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

My Solution (Swift)- Embed your size manipulation within the UICollectionViewDelegateFlowLayout.

我的解决方案 (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)
}

回答by Venkat S. Rao

You can change your if statement. You will need to have a reference to the collection views

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

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

回答by Illya Krit

The question was , how to separate two collection views in sizeForItemAtIndexPath. Why just not something like this?

问题是,如何在 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()
}

回答by Pierre

I've solved this problem by checking the rotation of the device and then reloading the layout. Checking the screen size and using this size to display my cell.

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

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

Then I defined the cells like this

然后我像这样定义了单元格

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

回答by progrmr

I've handled this by detecting the orientation change in the setBounds:method. We subclass the UICollectionViewand override the setBounds:method (see below). In flowLayoutForGallerySizewe create a new UICollectionViewFlowLayoutwith different spacing and itemSize depending on the size of the collection view.

我通过检测方法中的方向变化来处理这个问题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));
    }
}