iOS实现在collectionView顶部插入数据效果

有时候,我们会遇到这种需求,就是下拉刷新的时候,在

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

效果图

相关推荐
坏小虎9 小时前
Expo 快速创建 Android/iOS 应用开发指南
android·ios·rn·expo
光影少年10 小时前
Android和iOS原生开发的基础知识对RN开发的重要性,RN打包发布时原生端需要做哪些配置?
android·前端·react native·react.js·ios
北京自在科技10 小时前
Find My 修复定位 BUG,AirTag 安全再升级
ios·findmy·airtag
Digitally11 小时前
如何不用 USB 线将 iPhone 照片传到电脑?
ios·电脑·iphone
Sim14801 天前
iPhone将内置本地大模型,手机端AI实现0 token成本时代来临?
人工智能·ios·智能手机·iphone
Digitally1 天前
如何将 iPad 上的照片传输到 U 盘(4 种解决方案)
ios·ipad
报错小能手1 天前
ios开发方向——swift并发进阶核心 @MainActor 与 DispatchQueue.main 解析
开发语言·ios·swift
LcGero1 天前
Cocos Creator 业务与原生通信详解
android·ios·cocos creator·游戏开发·jsb
ii_best1 天前
lua语言开发脚本基础、mql命令库开发、安卓/ios基础开发教程,按键精灵新手工具
android·ios·自动化·编辑器
用户223586218202 天前
WebKit WebPage API 的引入尝试与自研实现
ios