Reload UICollectionView header or footer?

前端 未结 10 1105
余生分开走
余生分开走 2020-12-08 02:35

I have some data that is fetched in another thread that updates a UICollectionView\'s header. However, I\'ve not found an efficient way of reloading a supplementary view suc

相关标签:
10条回答
  • 2020-12-08 03:15

    My problem arose when frame sizes for the supplementary views changed upon invalidating the layout. It appeared that the supplementary views were not refreshing. It turns out they were, but I was building the UICollectionReusableView objects programmatically, and I was not removing the old UILabel subviews. So when the collection view dequeued each header view, the UILabels would pile up, causing erratic appearance.

    The solution was to build each UICollectionReusableView completely inside the viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath method, starting by a) removing all subviews from the dequeued cell, then b) getting the frame size from the item's layout attributes to allow adding the new subviews.

    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath 
    {
         yourClass *header = (yourClass *)[collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"identifier" forIndexPath:indexPath];
         [[header viewWithTag:1] removeFromSuperview]; // remove additional subviews as required
         UICollectionViewLayoutAttributes *attributes = [collectionView layoutAttributesForSupplementaryElementOfKind:kind atIndexPath:indexPath];
         CGRect frame = attributes.frame;
         UILabel *label = [[UILabel alloc] initWithFrame: // CGRectMake based on header frame
         label.tag = 1;
         [header addSubview:label];
         // configure label
         return header;
    }
    
    0 讨论(0)
  • 2020-12-08 03:21

    I just ran into the same problem, and I ended up looking up the view using its tag to edit a label:

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

    Like you said it is unnecessary to reload an entire section, which cancels out any animation on cells as well. My solution isn't ideal, but it's easy enough.

    0 讨论(0)
  • 2020-12-08 03:23

    Here's what I did to update only the section headers that are currently loaded in memory:

    • Add a weakToStrong NSMapTable. When you create a header, add the header as the weakly held key, with the indexPath object. If we reuse the header we'll update the indexPath.
    • When you need to update the headers, you can now enumerate the objects/keys from the NSMapTable as needed.
    
        @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
    
    0 讨论(0)
  • 2020-12-08 03:24
    [UIView performWithoutAnimation:^{
        [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:4]];
    }];
    
    [UIView performWithoutAnimation:^{
        [self.collectionView reloadData];
    }];
    
    0 讨论(0)
提交回复
热议问题