先放上效果图
设计思路
先获取到按照时间分类的相册集合,再利用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地址
下载地址
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/addevelopment/896324.html