web-dev-qa-db-ja.com

UICollectionViewおよび補足ビュー(ヘッダー)

補足ビューをヘッダーとしてUICollectionViewに追加しようとしています。動作させるのに問題があります。

カスタムのUICollectionViewFlowLayoutを使用して、常にフレームより少なくとも1ピクセル大きいcontentSizeを返します(UIFreshControlは、UICollectionViewがスクロールし、collectionView.contentSizeを直接設定しても何も実行されません)、invalidateLayoutおよびsectionInsertitemSizeが変更されます。

-(void)setSectionInset:(UIEdgeInsets)sectionInset {
    if (UIEdgeInsetsEqualToEdgeInsets(super.sectionInset, sectionInset)) {
        return;
    }

    super.sectionInset = sectionInset;

    [self invalidateLayout];

}

-(void) setItemSize:(CGSize)itemSize {
    if (CGSizeEqualToSize(super.itemSize, itemSize)) {
        return;
    }

    super.itemSize = itemSize;

    [self invalidateLayout];
}

- (CGSize)collectionViewContentSize
{
    CGFloat height = [super collectionViewContentSize].height;

    // Always returns a contentSize larger then frame so it can scroll and UIRefreshControl will work
    if (height < self.collectionView.bounds.size.height) {
        height = self.collectionView.bounds.size.height + 1;
    }

    return CGSizeMake([super collectionViewContentSize].width, height);
}

UICollectionReusableViewを持つUIViewであるUILabelクラスを作成しました:

@implementation CollectionHeaderView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"CollectionHeaderView" owner:self options:nil];

        if ([arrayOfViews count] < 1) {
            return nil;
        }

        if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
            return nil;
        }

        self = [arrayOfViews objectAtIndex:0];

        self.headerLabel.text = @"This is a header. There are many like it.";
        self.backgroundColor = [UIColor yellowColor];


    }
    return self;
}

それを実装しようとしています:

DatasetLayout *collectionViewFlowLayout = [[DatasetLayout alloc] init];
collectionViewFlowLayout.itemSize = CGSizeMake(360, 160);
collectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
collectionViewFlowLayout.minimumInteritemSpacing = 16;
collectionViewFlowLayout.minimumLineSpacing = 16;
collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);

UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
collectionView.backgroundColor = [UIColor yellowColor];
collectionView.delegate = self;
collectionView.dataSource = self;

クラスを登録します。

[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

デリゲートを実装します。

-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {

    CollectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView" forIndexPath:indexPath];

    headerView.headerLabel.text = @"Blarg!";

    return headerView;
}

この線

collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);

エラーの原因:

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:1150
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'

コメントアウトすると実行されますが、ヘッダーはありません。

何が間違っているのか、実装されていないのですか?

17
Padin215

同様の問題に直面しましたが、プログラムでUICollectionViewControllerをポップした後、アプリがクラッシュしました。何らかの理由で(SDKの単なるバグだと思います)self.collectionViewは、コントローラーが破壊された後も生きていたため、このエラーが発生しました。

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:1305
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'

解決策は、UICollectionViewControllerで-deallocをオーバーライドし、self.collectionViewを手動で解放することです。 ARCコード:

- (void)dealloc {

    self.collectionView = nil;
}

これが誰かの時間を節約することを願っています。

13
m8labs

このトピックの回答は非常に古く、iOS8およびiOS9では機能しません。上記の問題が解決しない場合は、次のトピックを確認してください。 ICollectionViewおよびSupplementary Viewのクラッシュ

[〜#〜] edit [〜#〜]

リンクが無効になった場合の答えは次のとおりです。

コレクションビューでカスタムレイアウトを使用している場合、そのデータソースがnilであるかどうかを確認します。

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

結果は次のようになります。

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    if (self.collectionView.dataSource != nil) {
        // Your layout code    
        return array;
    }
    return nil;
}

この変更により、次の問題が解決されます。

  • -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:]でのアサーションエラー

次のトピックも確認できますが、私の場合は何も解決しませんでした。

ICollectionViewでセクションヘッダーが非表示になっている場合の空のスペースの削除

それがあなたを助けることを願っています、そしてあなたは私がしたほど多くの時間を無駄にしないでしょう。

10
Michael

コードをクリーンアップし、IBで作成したUICollectionViewを削除し、すべてコードで作成しました。もう一度実行して別のエラーが発生し、IBでデリゲートまたはdataSourceを設定していないことに気付きました。やった:

self.collectionView.delegate = self;
self.collectionView.datasource = self;

しかし、それで十分ではなかったはずです。

したがって、IBで作成されたUICollectionViewを使用して、IBでdelgate/datasourceを設定するのではなく、コードで設定します。

[self.view bringSubviewToFront:self.collectionView];
self.collectionView.collectionViewLayout = collectionViewFlowLayout;
self.collectionView.backgroundColor = [UIColor orangeColor];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;

[self.collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];

[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

問題でした。コードでUICollectionViewをすべて作成するために再編集しました。

UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
collectionView.backgroundColor = [UIColor yellowColor];
collectionView.delegate = self;
collectionView.dataSource = self;

[collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];

[collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

[self.view addSubview:collectionView];

self.collectionView = collectionView;

そして、私は別のエラーが発生します:

*** Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:2249
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindSectionHeader with identifier CollectionHeaderView - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

それを理解しようとします。

編集:

それを理解し、ヘッダーを間違って登録していました:

[collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

切り替え先:

UINib *headerNib = [UINib nibWithNibName:@"CollectionHeaderView" bundle:nil];

[collectionView registerNib:headerNib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];

そしてすべてが動作します。 registerClass:が機能していませんでした。

7
Padin215

この回答は、データソースをチェックするメソッドを作成する他の回答と似ていますが、少し簡単です。この問題は、コレクションがリリースされた後のコレクションビューのレイアウトに関連しているようです。そこで、以下のようにレイアウトのプロパティをゼロにし、エラーが消えました。

deinit {
    let layout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    layout.estimatedItemSize = CGSizeZero
    layout.sectionInset = UIEdgeInsetsZero
    layout.headerReferenceSize = CGSizeZero
}
1
Chris Garrett

また、この迷惑なエラーが発生しました:

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-3347.44/UICollectionView.m:1400
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'

そして、私は何人かの人々がこのエラーを解決することを見つけました

- (void)dealloc {
    self.collectionView = nil;
}

またはSwiftで:

deinit {
    collectionView = nil
}

しかし、これらのどちらも私のクラッシュを解決しませんでした。私はいくつかのことを試してみましたが、次の「ハック」がこの厄介なバグを解決しました。

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    if collectionView.dataSource != nil {
        return someHeaderSize
    } else {
        return CGSizeZero
    }
}
1
Simon

エラーメッセージを見ると、データソースが設定されていないと表示されます。これで修正されます:

self.collectionView.dataSource = self;

View Controllerがデータソースプロトコルを実装していることを確認してください:

YourViewController : UIViewController<UICollectionViewDataSource>

1
Fran Sevillano

IOS9のバグ、viewcontrollerのdeallocセットレイヤーデリゲートnil。

- (void)dealloc{

    if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"9"]) {
        self.collectionView.layer.delegate = nil;
    }
}
0
liuyuning

私は同じ問題を抱えていて、同様に、ヘッダーを正しく登録していませんでした。ここにはいくつかのスレッドがあり、すべてがヘッダーを定義するためにニブを使用することを示唆していますが、私はそれを別の方法で行っており、正常に動作しています。

UICollectionReusableViewを継承するカスタムヘッダーSizeCollectionHeaderがあります。このように登録されます。

    [self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"UICollectionElementKindSectionHeader"
                                                                             withReuseIdentifier:@"SupplementaryViewIdentifier"];

正常に動作しています。

私の最初の問題は、このようなランダムな「Kind」値を持つことでした。

    [self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"SupplementaryViewKind"
                                                                             withReuseIdentifier:@"SupplementaryViewIdentifier"];

これはクラッシュします。

だから私はあなたがペン先を使う必要がないことをここで見ている人にコメントしたかった。

0
BROK3N S0UL

同じエラーが引き続き発生します。 collectionViewのCustomHeaderViewをセットアップしました。 CustomHeaderViewにコレクション再利用可能ビューのクラスがあり、識別子を設定していました。私はこれがなぜ失敗していたのかを理解しようと30分ほど試みました。

NS

ログを注意深く読む必要があります...学んだ教訓。

'種類のビューをデキューできませんでした:UICollectionElementKindSectionFooter

その理由は、ストーリーボードで-collectionView Identity Inspectorで、アクセサリ:セクションヘッダーとセクションフッターの両方をチェックしたためです。セクションヘッダーだけが必要でした。フッターのチェックを外すだけです...ビルドして実行してください。

0
Ronaldoh1

これを試して :

self.collectionView?.dataSource = nil
self.collectionView = nil

それは私のために働いた;)

0
user3369214