欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

按照日期对系统图片进行分类,并且支持多个section滑动选中

程序员文章站 2022-03-11 22:57:55
先放上效果图设计思路先获取到按照时间分类的相册集合,再利用CollectionView来展示获取到的图片,然后通过pan手势识别触摸区域内的子Cell。判断子Cell是选中还是取消。下面是具体实现步骤#获取图片资源利用PHCollectionList,获取到一个时刻集合。通过指定它的subType从而获取到以天为单位的时刻集合momentList。然后在遍历这个momentList的集合,从而获取里面的PHAssetCollection资源集合。然后从PHAssetCollection资源集合中取...

先放上效果图

按照日期对系统图片进行分类,并且支持多个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

相关标签: ios