ios - 滚动到 Collection View 中的项目会使应用程序崩溃

标签 ios objective-c uicollectionview

我想滚动到 viewWillAppearUICollectionView 的某个项目

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [collectionView_ scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:selectedIndex_ inSection:0]
                            atScrollPosition:UICollectionViewScrollPositionLeft
                                    animated:NO];
}

在 iOS 6 上,此代码使应用程序崩溃并返回

*** Assertion failure in -[UICollectionViewData layoutAttributesForItemAtIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UICollectionViewData.m:485
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'must return a UICollectionViewLayoutAttributes instance from -layoutAttributesForItemAtIndexPath: for path <NSIndexPath 0x13894e70> 2 indexes [0, 2]'

在 iOS7 上它不会崩溃,只是什么都不做。

滚动到正确的项目仅在 viewDidAppear 中有效,但我想在屏幕上显示正确项目中的集合。我试图在 viewDidLayoutSubviews 中滚动它,但它也崩溃了。将调用包装在 try-catch 中可以避免崩溃,但它仍然无法正常工作。

这有什么意义呢?是否无法在出现时显示正确的项目?

非常感谢。

编辑 1

我在 viewWillAppearviewDidLayoutSubviews 上打印了这个(selectedIndex_ 是 2,集合有 10 个项目):

UICollectionViewLayoutAttributes *test = [collectionView_ layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:selectedIndex_ inSection:0]];

两处结果都是这样

<UICollectionViewLayoutAttributes: 0x11b9ff20> index path: (<NSIndexPath: 0x11b9c450> {length = 2, path = 0 - 2}); frame = (0 0; 0 0);

编辑 2

这是我打印集合的 contentSize 的痕迹

2013-12-09 08:56:59.300 - didLoad {0, 0}
2013-12-09 08:56:59.315 - willAppear {0, 0}
2013-12-09 08:56:59.350 - viewDidLayoutSubviews {0, 0}
2013-12-09 08:56:59.781 - viewDidLayoutSubviews {3200, 223}
2013-12-09 08:56:59.879 - didAppear {3200, 223}
2013-12-09 08:56:59.882 - viewDidLayoutSubviews {3200, 223}

Collection View 是在 viewDidLoad 中以编程方式创建的

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
collectionView_ = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
[collectionView_ setTranslatesAutoresizingMaskIntoConstraints:NO];
[collectionView_ setDelegate:self];
[collectionView_ setDataSource:self];
[collectionView_ setShowsHorizontalScrollIndicator:NO];
[collectionView_ setPagingEnabled:YES];
[collectionView_ setBackgroundColor:[UIColor whiteColor]];
[collectionView_ registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:[MyCollectionViewCell collectionCellIdentifier]];
[scrollView_ addSubview:collectionView_];

scrollView_ 是通过 XIB 创建的(XIB 中唯一的控件。我需要另一个滚动条以将其他控件放在水平集合下方)。此方法的约束设置在updateViewConstraints

- (void)updateViewConstraints {
    [super updateViewConstraints];

    NSDictionary *views = [self viewsDictionary];
    NSDictionary *metrics = @{ @"bigMargin" : @12, @"collectionViewHeight" : @(collectionViewHeight_) };

    NSMutableString *verticalConstraints = [NSMutableString stringWithString:@"V:|[collectionView_(==collectionViewHeight)]"];

    [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[collectionView_(==scrollView_)]|"
                                                                        options:0
                                                                        metrics:nil
                                                                          views:views]];

    if (extendedInformationView_) {

        [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[extendedInformationView_(==scrollView_)]|"
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];

        [verticalConstraints appendFormat:@"-bigMargin-[extendedInformationView_]"];
    }

    if (actionListView_) {

        [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[actionListView_(==scrollView_)]|"
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];

        [verticalConstraints appendFormat:@"-bigMargin-[actionListView_]"];
    }

    [verticalConstraints appendString:@"-bigMargin-|"];

    [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalConstraints
                                                                        options:0
                                                                        metrics:metrics
                                                                          views:views]];

}

MyCollectionViewCell 在其 initWithFrame 方法中创建其所有控件,这里是返回单元格的方法。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    MyCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[MyCollectionViewCell collectionCellIdentifier]
                                                                           forIndexPath:indexPath];

    // Data filling

    return cell;   
}

最佳答案

我遇到了同样的问题,可以解决。首先,当您创建 UICollectionView 时,您必须指定一个框架及其宽度,无论高度如何,但宽度对于滚动到正确的项目非常重要。

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
collectionView_ = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, CGRectGetWidth([scrollView_ frame]), 0.0f)
                                     collectionViewLayout:layout];
[collectionView_ setDelegate:self];
[collectionView_ setDataSource:self];
[collectionView_ setBackgroundColor:[UIColor clearColor]];
[collectionView_ setTranslatesAutoresizingMaskIntoConstraints:NO];
[collectionView_ setShowsHorizontalScrollIndicator:NO];
[collectionView_ setPagingEnabled:YES];
[scrollView_ addSubview:collectionView_];

创建 UICollectionView 后,您必须告诉 View 需要更新其约束,因为在 iOS6 中您必须强制执行它,因此调用 updateViewConstraints:

[self updateViewConstraints]

重写方法updateViewConstraints,并在这里设置所有 View 约束。请记住在调用 super 之前删除 View 的所有约束(在您的代码中您没有删除它们),并在指标字典上设置 UICollectionView 的 width 并且不要使用 [ collectionView_(==scrollView_)] 因为有时会失败,主要是在 iOS6 中。

- (void)updateViewConstraints {

    [scrollView_ removeConstraints:[scrollView_ constraints]];
    [super updateViewConstraints];

    NSDictionary *views = [self viewsDictionary];
    NSDictionary *metrics = @{ @"bigMargin" : @12, @"collectionViewHeight" : @(collectionViewHeight_), @"viewWidth" : @(CGRectGetWidth([scrollView_ frame]) };

    NSMutableString *verticalConstraints = [NSMutableString stringWithString:@"V:|[collectionView_(==collectionViewHeight)]"];

    [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[collectionView_(==viewWidth)]|"
                                                                        options:0
                                                                        metrics:nil
                                                                          views:views]];

    if (extendedInformationView_) {

        [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[extendedInformationView_(==scrollView_)]|"
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];

        [verticalConstraints appendFormat:@"-bigMargin-[extendedInformationView_]"];
    }

    if (actionListView_) {

        [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[actionListView_(==scrollView_)]|"
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];

        [verticalConstraints appendFormat:@"-bigMargin-[actionListView_]"];
    }

    [verticalConstraints appendString:@"-bigMargin-|"];

    [scrollView_ addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalConstraints
                                                                        options:0
                                                                        metrics:metrics
                                                                          views:views]];

}

最后,要将 UICollectionView 滚动到正确的项目,请在 viewWillLayoutSubviews 上执行此操作,并且不要忘记检查 UICollectionView 的大小是否不为零以避免应用程序崩溃:

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    if (!CGSizeEqualToSize([collectionView_ frame].size, CGSizeZero)) {

        [collectionView_ scrollToItemAtIndexPath:_selectedRowItem_ inSection:0]
                                atScrollPosition:UICollectionViewScrollPositionLeft
                                        animated:NO];
    }
}

就是这样。希望对您有所帮助!

关于ios - 滚动到 Collection View 中的项目会使应用程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20355713/

相关文章:

ios - 使用 OCMock 对本地对象或依赖注入(inject)进行单元测试?

ios - MapBox 导航舱无法在我使用 Xcode 9.2 的地方使用 ObjectiveC 安装

iOS - 以编程方式将应用程序的自定义 URI 添加到存储在日历中的事件

ios - 页面控件在完全转到下一页之前切换页面

ios - UICollectionView 内部的 UITableView 处理触摸。

ios - 在行中间展开一个 UICollectionView

iOS Swift 条码读取

ios - 如何清除导航堆栈以使后退按钮不出现?

ios - KVO 在 UITableView 中观察模型变化的最佳实践

iphone - 在 UISearchBar 上设置第一个文本