按照日期对系统图片进行分类,并且支持多个section滑动选中
先放上效果图
设计思路
先获取到按照时间分类的相册集合,再利用CollectionView来展示获取到的图片,然后通过pan手势识别触摸区域内的子Cell。判断子Cell是选中还是取消。下面是具体实现步骤
#获取图片资源
利用PHCollectionList,获取到一个时刻集合。通过指定它的subType从而获取到以天为单位的时刻集合momentList。然后在遍历这个momentList的集合,从而获取里面的PHAssetCollection资源集合。然后从PHAssetCollection资源集合中取出相应的资源文件PHAsset,得到每天的照片数量。
通过以上方法我们就可以得到一个二维数组 Array[日期][具体照片]。完整实现代码如下
NSMutableArray* momentArray = [NSMutableArray array];
PHFetchOptions *momentOptions = [[PHFetchOptions alloc]init];
momentOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"startDate" ascending:NO]];
PHFetchResult* collectionList = [PHCollectionList fetchCollectionListsWithType:PHCollectionListTypeMomentList subtype:PHCollectionListSubtypeMomentListCluster options:momentOptions];
[collectionList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//创建一个时刻存放数组
PHCollectionList* momentList = (PHCollectionList*) obj;
NSMutableArray* dayArray = [NSMutableArray array];
//获取时刻里面的Asset集合
PHFetchResult<PHAssetCollection*>* result = [PHAssetCollection fetchMomentsInMomentList:momentList options:momentOptions];
[result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
PHAssetCollection* collection = (PHAssetCollection*) obj;
//设置筛选条件
PHFetchOptions *asstsOptions = [[PHFetchOptions alloc]init];
asstsOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
//获取Asset集合里面的Asset
PHFetchResult<PHAsset*>* assetResult = [PHAsset fetchAssetsInAssetCollection:collection options:asstsOptions];
//遍历获取Asset
[assetResult enumerateObjectsUsingBlock:^(PHAsset * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[dayArray addObject:[AMPHAssetsModel modelWithPHAsset:obj]];
}];
}];
if (dayArray.count > 0) {
AMAlbumModel* album = [[AMAlbumModel alloc] init];
album.name = [NSDate stringFromDate:momentList.startDate withFormat:@"yyyy年MM月dd"];
album.assetsArray = dayArray;
[momentArray addObject:album];
}
}];
CollectionView实现节标题悬浮
数据导入
以一日为一个section,这日内的所有资源Asset为Cell。得到了一个多节的CollectionView。
为CollectionView添加sectioneHeader
与TableView不同的是,要实现UICollectionview的sectionHeader需要,现在UICollectionView里面注册一个UICollectionReusableView并且为它指定好复用标识
[collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"];
注册好header标识之后需要,通过实现UICollectionViewDataSource协议。为sectionHeaderView添加上我们想要的内容
- (UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
这里要注意的是
如果没有在sectionHeaderView上使用全局的控件 则需要在通过标识获取到复用的sectionHeaderView之后需要对之前添加在上面的View进行删除
实现sectionHeader悬浮状态
与tableView不同的是,我们在成功设置好了sectionHeader之后,滚动时发现sectionHeaderView无法实现类似于tableView的悬浮效果,所以这里我们需要在collectionLayout里面将layout.sectionHeadersPinToVisibleBounds = YES
layout.sectionHeadersPinToVisibleBounds = YES;
CollectionView实现滑动多行选中
原理分析
通过使用UIPanGestureRecognizer手势,来获取到滑动触摸点point,然后通过CollectionView的indexPathForItemAtPoint方法获取到具体触摸到那个cell,并获取到其indexPath。从而实现获取到滑动过程中所选中的cell,并改变其选中状态。
下面分为三步来处理触摸事件。
触摸开始
首先获取到触摸点的Cell,通过判断cell的选中状态来,决定这个滑动是选中cell,还是取消已经选中的cell。并且记录下该cell的indexPath,作为起点cell.实现代码
if (pan.state == UIGestureRecognizerStateBegan) {
if (!indexPath) {
_beginSelect = NO;
}
else {
_beginSelect = YES;
}
if(_beginSelect){
model.selected = !mode.selected
}
}
触摸事件进行中
记录下我们滑动过程中所经过的cell。由于滑动过程中所经过的point可能会在同一个cell当中所以我们先要进行。判重操作。经过去重操作后。我们需要将这些选中的cell。按照第一步中所获取的状态进行对比,如果滑动开始时是选中状态,而选中的cell确实未选中状态,则改变该cell的状态。如果是相同的则不与改变。
判断开始选中的indexPath和最后滑到的indexPath的大小。如果开始选中的是大于最后的,则代表从开始的cell向前滑动,如果开始大于结束的,则代表是向后滑动。
注意由于我们这里是多个section,不能单单通过indexPath.row 来判断开始的indexPath和结束的indexPath的大小。需要先将二维数组转化为一位数组进行判断。
下面是将二维的图片数组下标,转换为一维的下标和将一维的下标转化为二维图片数组的下标
//将indexPath里面的row和section 转化为递增的数据
- (NSInteger) orderIndexWithIndexPath:(NSIndexPath*) path{
NSInteger sectionConout = 0;
for (int i = 0; i < path.section; i++) {
AMAlbumModel* model = self.dataArray[i];
sectionConout += model.assetsArray.count;
}
return path.row + sectionConout;
}
- (NSIndexPath*) indexPathWithIndex:(NSInteger) index {
NSInteger division = 0;
NSInteger res = index;
NSInteger count = 0;
// NSLog(@"index %ld",index);
for(int i = 0; i < self.dataArray.count;i++){ // 2 1 1 3
AMAlbumModel* model = self.dataArray[i];
count += model.assetsArray.count;
if (index >= count) {
//大于之前的和 则跳转到下一个section
division++;
}
else { //小于等于之前的和 则算出之前的section有多少 在求出row 并且终止循环
NSInteger sum = count - model.assetsArray.count;
res = index - sum;
break;
}
}
NSIndexPath* path = [NSIndexPath indexPathForRow:res inSection:division];
// NSLog(@"res %ld",res);
// NSLog(@"over");
return path;
}
结束滑动
重置之前滑动的状态。并且清空第一步第二步所使用的数组。
Demo地址
本文地址:https://blog.csdn.net/u014017974/article/details/107363769
上一篇: 常见四个“头缺失或不安全”问题