有时候,我们会遇到这种需求,就是下拉刷新的时候,在
collectionView顶部插入数据,这个时候,需要我们注意
主要有两点
1 关闭隐式动画
由于我们使用insert在collectionView顶部插入数据是有从头部插入的隐式动画的,这个不符合我们的需要,所以要关闭隐式动画 [CATransaction setDisableActions:YES];
2 我们执行过插入数据操作之后,还要将偏移量滚动到之前展示的位置达到在页面顶部插入数据的效果,所以我们要精确的捕获到插入结束的时机,就需要用到performBatchUpdates 方法,在结束的回调中设置偏移量
3 因为涉及到如果没有上一页了,要修改列表的头部,
因为刷新视图就是在头部中,这个时候(头部在顶部,未展示出来),我们需要使用performBatchUpdates 刷新列表,而不能使用reloadData,因为reloadData 刷新头部的时候,会造成列表的cell偏移, 而performBatchUpdates 则不会
代码
//
// LBUpdateBatchViewController.m
// TEXT
//
// Created by mac on 2025/1/4.
// Copyright © 2025 刘博. All rights reserved.
//
#import "LBUpdateBatchViewController.h"
#import "PerformBatchCell.h"
@interface LBUpdateBatchViewController () <UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) UIButton *firstButton;
@property (nonatomic, strong) UIButton *secondButton;
@property (nonatomic, strong) UIButton *thirdButton;
@property (nonatomic, assign) NSInteger flag;
@property (nonatomic, assign) NSInteger itemCount;
@end
@implementation LBUpdateBatchViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.flag = 1;
self.itemCount = 20;
[self.view addSubview:self.collectionView];
[self.view addSubview:self.firstButton];
[self.view addSubview:self.secondButton];
[self.view addSubview:self.thirdButton];
// Do any additional setup after loading the view.
}
- (void)firstClick
{
self.flag = 0;
[self.collectionView reloadData];
}
- (void)secondClick
{
self.flag = 2;
[self.collectionView performBatchUpdates:nil completion:nil];
}
- (void)loadPreviousPage
{
self.itemCount += 6;
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 6; i ++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[array addObject:indexPath];
}
[CATransaction setDisableActions:YES];
[self.collectionView performBatchUpdates:^{
[self.collectionView insertItemsAtIndexPaths:array];
} completion:^(BOOL finished) {
[CATransaction setDisableActions:NO];
if (finished) {
CGRect frame = [self.collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:6 inSection:0]].frame;
[self.collectionView setContentOffset:CGPointMake(0, frame.origin.y - 100)];
self.flag --;
if (self.flag <= 0) {
///注意,这里一定要用 performBatchUpdates 不能用reloadData
[self.collectionView performBatchUpdates:nil completion:nil];
}
}
}];
}
#pragma mark - UICollectionViewDelegate, UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.itemCount;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
UICollectionReusableView *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"header" forIndexPath:indexPath];
header.backgroundColor = [UIColor cyanColor];
return header;
}
return nil;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
CGFloat height = 0;
if (self.flag > 0) {
height = 100;
}
return CGSizeMake(300, height);
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PerformBatchCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
NSString *title = [NSString stringWithFormat:@"%ld", indexPath.item];
[cell updateWithText:title];
return cell;
}
- (UICollectionView *)collectionView
{
if (!_collectionView) {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(100, 100);
layout.minimumLineSpacing = 10;
layout.minimumInteritemSpacing = 10;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(10, 100, 300, 600) collectionViewLayout:layout];
[_collectionView registerClass:[PerformBatchCell class] forCellWithReuseIdentifier:@"cell"];
[_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];
_collectionView.delegate = self;
_collectionView.dataSource = self;
}
return _collectionView;
}
- (UIButton *)firstButton
{
if (!_firstButton) {
_firstButton = [UIButton buttonWithType:UIButtonTypeCustom];
_firstButton.frame = CGRectMake(100, 100, 200, 100);
_firstButton.titleLabel.font = [UIFont systemFontOfSize:14];
_firstButton.backgroundColor = [UIColor redColor];
[_firstButton setTitle:@"隐藏头部并reloadData" forState:UIControlStateNormal];
[_firstButton addTarget:self action:@selector(firstClick) forControlEvents:UIControlEventTouchUpInside];
}
return _firstButton;
}
- (UIButton *)secondButton
{
if (!_secondButton) {
_secondButton = [UIButton buttonWithType:UIButtonTypeCustom];
_secondButton.frame = CGRectMake(100, 250, 200, 100);
_secondButton.backgroundColor = [UIColor greenColor];
[_secondButton setTitle:@"展示头部并performBatchUpdates" forState:UIControlStateNormal];
[_secondButton addTarget:self action:@selector(secondClick) forControlEvents:UIControlEventTouchUpInside];
_secondButton.titleLabel.font = [UIFont systemFontOfSize:14];
}
return _secondButton;
}
- (UIButton *)thirdButton
{
if (!_thirdButton) {
_thirdButton = [UIButton buttonWithType:UIButtonTypeCustom];
_thirdButton.frame = CGRectMake(100, 400, 200, 100);
_thirdButton.backgroundColor = [UIColor blueColor];
[_thirdButton setTitle:@"模拟加载上一页" forState:UIControlStateNormal];
[_thirdButton addTarget:self action:@selector(loadPreviousPage) forControlEvents:UIControlEventTouchUpInside];
_thirdButton.titleLabel.font = [UIFont systemFontOfSize:14];
}
return _thirdButton;
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
效果图