23

我有一个带有 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: 永远不会被调用。

希望你明白我的意思。如果您需要更多信息,请告诉我:)

4

7 回答 7

36

这个答案很晚,但接受的答案对我不起作用。我同情 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 保持方向之间的滚动位置。只有当它是正方形时,相同的单元格才会居中。

于 2013-11-18T12:59:43.290 回答
8

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

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

    [self.collectionView.collectionViewLayout invalidateLayout];
}
于 2014-12-11T20:20:28.297 回答
3

我不知道它是否对某人有帮助,但最后一个答案都没有帮助我,因为我正在将一些UIViews用于UIScrollView.

我根据某些事件以编程方式打开 UIViews。所以我不能使用- (void) willRotateToInterfaceOrientation:and invalidateLayoutorreloadData因为:
1. invalidateLayout “发生在下一个视图布局更新周期中”。
2. reloadData “为了提高效率,集合视图只显示那些可见的单元格和补充视图。”

对我有用的是使用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帮助我修复它。

于 2014-08-07T16:24:43.317 回答
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()
    }
}
于 2015-11-19T23:44:35.193 回答
2

iOS8:我可以使警告静音的唯一方法是在旋转到较大尺寸时在过渡期间调用无效,在旋转到较小尺寸时在过渡之前调用。

    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) {
    }];
于 2015-05-26T15:49:54.237 回答
1

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

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

每次视图出现时都会显示警告。警告的原因很清楚,我们已经在 UICollectionView 的左右定义了 section insets。检查界面构建器,您将在指标中看到定义的那些值。

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

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

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

于 2015-04-02T09:29:51.297 回答
0

一种解决方案是使用 KVO 并监听集合视图的父视图框架的变化。调用 -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];
}
于 2013-05-31T18:58:26.227 回答