当前位置: 移动技术网 > 移动技术>移动开发>Android > 按照日期对系统图片进行分类,并且支持多个section滑动选中

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

2020年07月17日  | 移动技术网移动技术  | 我要评论

先放上效果图

ezgif-2-b5556f54d169.gif

设计思路

先获取到按照时间分类的相册集合,再利用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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网