[iOS开发]IGListKit框架初学

Posted Billy Miracle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[iOS开发]IGListKit框架初学相关的知识,希望对你有一定的参考价值。

大多数 ios 应用中列表都是通过 UICollectionView 实现。虽然它性能强大,API 丰富易用,但依旧存在一些不足。常见的比如,更新页面时如果调用 reloadData 会造成屏幕闪烁。IGListKit主流的使用和例子都是Swift的,接下来,我就通过我的一个朋友圈仿写来为大家介绍一下其使用Objective-C来完成的使用过程。先看一下ViewController里面的使用方法:

- (IGListAdapter *)adapter 
    if (!_adapter) 
        /**
         默认初始化IGListAdapter
         参数1:IGListAdapterUpdater,是一个遵循了IGListUpdatingDelegate的对象,它处理每行更新。
         参数2:viewController,是包含IGListAdapter的UIViewController。 可以用来push到其他控制器
         参数3:workingRangeSize是工作范围的大小,它可以让你为刚好在可见范围之外的视图做一些准备工作,暂时没用到给0。
         */
        _adapter = [[IGListAdapter alloc] initWithUpdater:[[IGListAdapterUpdater alloc] init] viewController:self workingRangeSize:0];
    
    return _adapter;

Model数据模型

[self.view addSubview:self.collectionView];
//给adapter赋值collectionView
self.adapter.collectionView = self.collectionView;
//给adapter赋值dataSource
self.adapter.dataSource = self;

其中里面IGListAdapterUpdater是数据控制协议,collectionView也是放在里面作为其属性。然后需要按照需要定义自己项目需要的数据模型。给出我的用户的模型例子:

@interface AuthorModel : NSObject
<IGListDiffable>

@property (nonatomic, strong) NSNumber *authorId;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *headImageUrl;
@property (nonatomic, strong) NSString *pos;

- (instancetype)initWithId:(NSNumber *)authorId name:(NSString *)name headImage:(NSString *)headImage;
@end

@implementation AuthorModel

- (instancetype)initWithId:(NSNumber *)authorId name:(NSString *)name headImage:(NSString *)headImage 
    if (self = [super init]) 
        self.authorId = authorId;
        self.name = name;
        self.headImageUrl = headImage;
        self.pos = [self uuid];
    
    return self;


- (nonnull id<NSObject>)diffIdentifier 
    return self.pos;


- (NSString *)uuid 
    CFUUIDRef uuid_ref = CFUUIDCreate(NULL);
    CFStringRef uuid_string_ref = CFUUIDCreateString(NULL, uuid_ref);
    NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuid_string_ref];
    CFRelease(uuid_ref);
    CFRelease(uuid_string_ref);
//    NSLog(@"%@", uuid);
    return [uuid lowercaseString];



- (BOOL)isEqualToDiffableObject:(AuthorModel *)object 
    if (self == object) //指针地址比较
        return YES;
    
    if (![object isKindOfClass:[self class]]) 
        return NO;
    
    return [self.pos isEqualToString:object.pos];


@end

需要注意的是model类都实现了IGListDiffable协议,该协议的作用是使用额外一些内存空间,降低时间复杂度到O(n),并且能准确获取所有Insert/Delete/Move操作。内部用哈希的方式实现。协议中需要实现两个数据Model的对比方法以判断其异同。例如Model中有数组元素,可以先判断数据个数,再循环判断数组里面的对象。在初次尝试时,用户的diffIdentifier我使用的是他的authorId,但是这样会导致一个问题。我们的“朋友圈”每个用户只能出现一次,因为它会判定你这是一个人,拒绝重复出现。我投机取巧,使用UUID作为判定一个人的标志,因为我们实际上是可以让一个人发好几次朋友圈的。在实际的应用中,把每个朋友圈的信息和朋友圈的id绑定上,或许是一个很好的解决办法,为了美观,也可以将每个朋友圈的信息整合到一个section中,毕竟更加美观且符合人类逻辑。这里的例子仅供学习参考,十分简陋,没有考虑太多。

IGListAdapterDataSource

看过了数据模型的定义方法,接下来,我们看一下IGListAdapterDataSource的数据源方法。

// MARK: IGListAdapterDataSource
//对于不同listAdapter的数据
- (NSArray<id<IGListDiffable>> *)objectsForListAdapter:(IGListAdapter *)listAdapter 
    if ([self.selectedClass isEqualToString:self.segments[0][1]]) 
        return self.data;
    
    
    NSMutableArray *arrM = [NSMutableArray array];
    Class class = NSClassFromString(self.selectedClass);
    for (id obj in self.data) 
        if ([obj isKindOfClass:class]) 
            [arrM addObject:obj];
        
    
    return arrM;

//对于不同的object返回不同的sectionController
- (IGListSectionController *)listAdapter:(IGListAdapter *)listAdapter sectionControllerForObject:(id)object 
    if ([object isKindOfClass:[ContentModel class]]) 
        return [ContentSectionController new];
     else if ([object isKindOfClass:[ImageModel class]]) 
        return [ImageSectionController new];
     else 
        return [AuthorSectionController new];
    

//没有数据返回的视图
- (UIView *)emptyViewForListAdapter:(IGListAdapter *)listAdapter 
    return nil;

Model的不同状态来返回不同的控制类。以实现对不同布局逻辑的代码分离。每一个Section具体到不同的SectionController里面去。

SectionController

我在这里使用显示图片的Section演示如何使用SectionController

- (instancetype)init 
    self = [super init];
    if (self) 
        self.minimumInteritemSpacing = 0;
        self.minimumLineSpacing = 0;
        self.inset = UIEdgeInsetsMake(0, 55, 0, 55);
    
    return self;


- (NSInteger)numberOfItems 
    //相当于UICollectionView一个indexPath.setion中有几个row
    return _model.imageUrls.count;


- (CGSize)sizeForItemAtIndex:(NSInteger)index 
    CGFloat width = [self.collectionContext containerSize].width - 110;
    CGFloat itemSize = floor(width / 3);
    //返回cell大小
    return CGSizeMake(itemSize, itemSize);


- (UICollectionViewCell *)cellForItemAtIndex:(NSInteger)index 
    //返回cell
    ImageCell *cell = [self.collectionContext dequeueReusableCellOfClass:[ImageCell class] forSectionController:self atIndex:index];
    [cell.myImageView sd_setImageWithURL:_model.imageUrls[index] placeholderImage:nil options:SDWebImageProgressiveLoad completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) 
        cell.myImageView.image = [self cropSquareImage:image];
    ];
    return cell;


- (void)didUpdateToObject:(id)object 
    //绑定model
    _model = object;


- (void)didSelectItemAtIndex:(NSInteger)index 
    //一个row的点击事件
    return;

在每个SectionController里面,控制具体的index要什么类型的cell,再创建cell放上去。这样逻辑一层层下放分离,十分厉害。

更新方法:

section中

可以在具体的sectionController里面实现更新具体indexcell的方法:

[self.collectionContext performBatchAnimated:YES updates:^(id<IGListBatchContext>  _Nonnull batchContext) 
    [batchContext reloadInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:0]];
 completion:nil];

ViewController中

[self.adapter performUpdatesAnimated:YES completion:nil];

效果图:

我这个是仿照的朋友圈,又按照别人的demo更改了一下下数据处理,我们一起来看一下效果。
对于不同的cell我们可以展开收起,实现了基于计算高度的自适应行高。我们还可以使用上面的控制器选择器来筛选不同的数据类型:


以上就是我对IGListKit框架初次学习的总结啦!这个框架的动画我真的是爱了爱了😍😍😍

开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系

以上是关于[iOS开发]IGListKit框架初学的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 IGListKit 强制重新加载所有部分?

如何在 swift 中使用 IGListKit 创建一个两列集合视图列表

IGListkit 网络责任

当调用 `performUpdates(:)` 时,由 IGListKit 提供支持的 UICollectionView 停止滚动

如何使用 IGListKit 滚动到部分的底部

IGListKit - IGListSectionController 中的动态 .minimumLineSpacing