UICollectionViewFlowLayout在方向更改时不会失效

时间:2013-05-02 15:20:37

标签: ios uicollectionview uicollectionviewlayout

我有一个带有UICollectionViewFlowLayout的UICollectionView。我还实现了UICollectionViewDelegateFlowLayout协议。

在我的数据源中,我有一堆UIViewControllers响应自定义协议,所以我可以询问它们的大小和其他一些东西。

在FlowLayout委托中请求sizeForItemAtIndexPath:时,我返回从我的协议获得的项目大小。实现我的协议的ViewControllers根据方向返回不同的项目大小。

现在,如果我将设备方向从纵向更改为横向,则没有问题(项目在横向上更大)但如果我将其更改回来,我会收到此警告:

    the item width must be less that the width of the UICollectionView minus the section insets left and right values.
    Please check the values return by the delegate.

它仍然有效,但我不喜欢它得到警告所以也许你可以告诉我我做错了什么。还有另一个问题。如果我没有告诉我的collectionViews collectionViewLayout在willAnimateRotationToInterfaceOrientation中失效:从不调用sizeForItemAtIndexPath:。

希望你理解我的意思。如果您需要其他信息,请告诉我们:)

7 个答案:

答案 0 :(得分:35)

这个答案很晚,但接受的答案对我不起作用。我同情OP需要一个即兴发射的UICollectionViewFlowLayout。我建议在视图控制器中使布局无效实际上是最好的解决方案。

我想要一个单独的水平滚动细胞线,在视图中居中,纵向和横向。

我将UICollectionViewFlowLayout子类化。

我覆盖prepareLayout以重新计算插入,然后调用[super prepareLayout]。

我覆盖了collectionViewContentSize的getter以使某些内容大小正确。

即使边界随着重新定位而变化,布局也没有自行失效。

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    // does the superclass do anything at this point?
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    // do whatever else you need before rotating toInterfaceOrientation

    // tell the layout to recalculate
    [self.collectionViewLayout invalidateLayout];
}

UICollectionViewFlowLayout维护方向之间的滚动位置。如果它是正方形,则相同的单元格将仅居中

答案 1 :(得分:7)

我在这里使用了两个答案的组合来做我们都想要做的事情真的是使集合视图看起来像表视图但不使用UITableView并在单个列中获取项目(最有可能)

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

    [self.collectionView.collectionViewLayout invalidateLayout];
}

答案 2 :(得分:3)

@ meelawsh答案的变体,但在Swift中,没有self.sizeForCollectionView属性:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    guard let collectionView = self.collectionView else {
        return
    }

    if size.width > collectionView.frame.width {
        // bigger

        let animation: (UIViewControllerTransitionCoordinatorContext)->(Void) = {
            context in
            collectionView.collectionViewLayout.invalidateLayout()
        }

        coordinator.animateAlongsideTransition(animation, completion: nil)
    } else {
        // smaller
        collectionView.collectionViewLayout.invalidateLayout()
    }
}

答案 3 :(得分:2)

一种解决方案是使用KVO并监听对集合视图的superview框架的更改。调用-reloadData将起作用并消除警告。这里有一个潜在的时间问题......

// -loadView
[self.view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];

// -dealloc
[self.view removeObserver:self forKeyPath:@"frame"];

// KVO Method
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    [collectionView_ reloadData];
}

答案 4 :(得分:2)

我不知道它是否对某人有帮助,但最后一个答案都没有帮助我,因为我在UIViews中使用了一些UIScrollView。登记/> 我会根据某些事件以编程方式打开UIViews。所以我无法使用- (void) willRotateToInterfaceOrientation:invalidateLayoutreloadData,因为:
1. invalidateLayout&#34;在下一个视图布局更新周期中发生。&#34;
2. reloadData&#34;为了提高效率,集合视图仅显示可见的单元格和补充视图。&#34;

对我有用的是使用collectionView的父级(UIView)的宽度:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
int currentWidth = self.frame.size.width;

UIEdgeInsets sectionInset = [(UICollectionViewFlowLayout *)collectionView.collectionViewLayout sectionInset];
int fixedWidth = currentWidth - (sectionInset.left + sectionInset.right);


由于某种原因,collectionView框架在调用此函数时具有纵向宽度...使用int currentWidth = self.frame.width帮我修复它。

答案 5 :(得分:2)

iOS8:我可以使警告静音的唯一方法是在转换到较大尺寸时转换过程中调用invalidate,然后在转换到较小尺寸时转换。

    self.sizeForCollectionView = size; //used to determine collectionview size in sizeForItem
    if (size.width <= size.height) {
        [self.collectionView.collectionViewLayout invalidateLayout];
    }

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        if (size.width > size.height) {
            [self.collectionView.collectionViewLayout invalidateLayout];
        }
    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
    }];

答案 6 :(得分:1)

@ 0mahc0的回答对我有用,但只是部分回答。

我没有旋转问题,因为我强制我的应用仅处于纵向模式,但我的解决方案可以帮助其他人解决同样的问题。

每次出现视图时都会显示警告。警告的原因很清楚,我们已经定义了UICollectionView左右两侧的插件。检查界面构建器,您将在度量标准中看到定义的值。

@ 0mahc0的解决方案有效,但我想将单元格拉伸到最大宽度,所以我删除了部分的插图,否则我会左右边缘。

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
    return UIEdgeInsetsZero;
}

您可以转到界面构建器并将值更改为左右插入的零,而不是实现委托方法。