[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
里面实现更新具体index
的cell
的方法:
[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
框架初次学习的总结啦!这个框架的动画我真的是爱了爱了😍😍😍
以上是关于[iOS开发]IGListKit框架初学的主要内容,如果未能解决你的问题,请参考以下文章
如何在 swift 中使用 IGListKit 创建一个两列集合视图列表
当调用 `performUpdates(:)` 时,由 IGListKit 提供支持的 UICollectionView 停止滚动
IGListKit - IGListSectionController 中的动态 .minimumLineSpacing