42

UICollectionViewのヘッダーを更新する別のスレッドでフェッチされるデータがあります。ただし、ヘッダーやフッターなどの補足ビューをリロードする効率的な方法は見つかりませんでした。

を呼び出すことはできますcollectionView reloadSections:が、これによりセクション全体がリロードされ、不要になります。collectionView reloadItemsAtIndexPaths:細胞のみをターゲットにしているようです(補足ビューではありません)。また、ヘッダー自体の呼び出しsetNeedsDisplayも機能していないようです。私は何かが足りないのですか?

4

12 に答える 12

35

使用することもできます(怠惰な方法)

collectionView.collectionViewLayout.invalidateLayout() // swift

[[_collectionView collectionViewLayout] invalidateLayout] // objc

より複雑なのは、コンテキストを提供することです

collectionView.collectionViewLayout.invalidateLayout(with: context) // swift

[[_collectionView collectionViewLayout] invalidateLayoutWithContext:context] // objc

次に、コンテキストを自分で作成または構成して、何を更新する必要があるかを通知できます。UICollectionViewLayoutInvalidationContextを参照してください。

オーバーライドできる機能があります。

invalidateSupplementaryElements(ofKind:at:) // swift

もう 1 つのオプションは (正しいヘッダー/フッター/補足ビューを既に読み込んでいる場合)、次の関数のいずれかを使用して取得するよりも新しいデータでビューを更新することだけです。

supplementaryView(forElementKind:at:) // get specific one visibleSupplementaryViews(ofKind:) // all visible ones

で表示されているセルについても同じことが言えますvisibleCells。ビューを完全にリロードせずにビューを取得するだけの利点は、セルがその状態を保持することです。これは、セルをリロードした後にその状態が失われるため、スワイプを使用して削除/編集/などする場合、テーブル ビュー セルでは特に便利です。

狂信的だと感じる場合は、もちろん、ジェネリックを使用して特定の種類のセル/補足ビューのみを取得する拡張機能を作成することもできます

if let view = supplementaryView(forType: MySupplementaryView.self, at: indexPath) {
    configure(view, at indexPath)
}

これは、例のビューをクラス名で登録/デキューする関数があることを前提としています。私はこれについてここに投稿しました

于 2014-02-20T15:42:39.347 に答える
10

同じ問題に遭遇したばかりで、タグを使用してビューを検索してラベルを編集することになりました。

UICollectionReusableView *footer = (UICollectionReusableView*)[self.collectionView viewWithTag:999];
UILabel *footerLabel = (UILabel*)[footer viewWithTag:100];

あなたが言ったように、セクション全体をリロードする必要はありません。これにより、セルのアニメーションもキャンセルされます。私の解決策は理想的ではありませんが、簡単です。

于 2013-01-13T00:36:55.257 に答える
2

2 つの方法があります。

1. 可変モデルを作成して、最終的に利用可能になるデータをバックアップします。UICollectionReusableView の継承されたクラスで KVO を使用して、変更を観察し、利用可能になった新しいデータでヘッダー ビューを更新します。

[model addObserver:headerView
        forKeyPath:@"path_To_Header_Data_I_care_about"
           options:(NSKeyValueObservingOptionNew |
                    NSKeyValueObservingOptionOld)
           context:NULL];

次に、ヘッダービューにリスナーメソッドを実装します

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context

2. 通知リスナーをビューに追加し、データが正常に利用可能になったときに通知を投稿します。欠点は、これがアプリケーション全体であり、クリーンなデザインではないことです。

// place in shared header file
#define HEADER_DATA_AVAILABLE @"Header Data Available Notification Name"

// object can contain userData property which could hole data needed. 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(headerDataAvailable:) name:HEADER_DATA_AVAILABLE object:nil];

[[NSNotificationCenter defaultCenter] postNotificationName:HEADER_DATA_AVAILABLE object:nil];
于 2012-12-12T17:03:43.587 に答える
1

現在メモリにロードされているセクションヘッダーのみを更新するために行ったことは次のとおりです。

  • weakToStrong を追加しますNSMapTable。ヘッダーを作成するときは、indexPath オブジェクトを使用して、ヘッダーを弱く保持されたキーとして追加します。ヘッダーを再利用すると、indexPath が更新されます。
  • ヘッダーを更新する必要がある場合、必要に応じて からオブジェクト/キーを列挙できるNSMapTableようになりました。

    @interface YourCVController ()
        @property (nonatomic, strong) NSMapTable *sectionHeaders;
    @end

    @implementation YourCVContoller

    - (void)viewDidLoad {
        [super viewDidLoad];
        // This will weakly hold on to the KEYS and strongly hold on to the OBJECTS
        // keys == HeaderView, object == indexPath
        self.sectionHeaders = [NSMapTable weakToStrongObjectsMapTable];
    }

    // Creating a Header. Shove it into our map so we can update on the fly
    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
    {
        PresentationSectionHeader *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"presentationHeader" forIndexPath:indexPath];
        // Shove data into header here
        ...
        // Use header as our weak key. If it goes away we don't care about it
        // Set indexPath as object so we can easily find our indexPath if we need it
        [self.sectionHeaders setObject:indexPath forKey:header];
        return header;
    }

    // Update Received, need to update our headers
    - (void) updateHeaders {
        NSEnumerator *enumerator = self.sectionHeaders.keyEnumerator;
        PresentationSectionHeader *header = nil;
        while ((header = enumerator.nextObject)) {
            // Update the header as needed here
            NSIndexPath *indexPath = [self.sectionHeaders objectForKey:header];
        }
    }

    @end
于 2015-01-05T17:06:01.910 に答える