[iOS]自定义图片选择器

Demo:https://github.com/Gamin-fzym/GACustomPhotoSelector
本文的产生,因今年夏季被面试时有被问到的一个问题。有没有自定义过相片选择器?于是抽空查资料写一个简单demo放在这里。
内容:
1.写了一个“自定义图片选择器”。
2.获取到图片后为了剪切图片使用了工具“PureCamera”。
3.将编辑后的图片保存到自定义相册。
4.最后为自定义图片选择器添加了多选功能。

demo示意图:


首页(HomeViewController)
首页示意图:

#import "HomeViewController.h"
#import <CoreServices/CoreServices.h>
#import "TOCropViewController.h"
#import "PureCamera.h"
#import "ListViewController.h"
#import "SVProgressHUD.h"
#import "GACustomSelectPIC.h"
#import "GACustomSelectProtocol.h"
#import "GAPublicMethod.h"

@interface HomeViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate, TOCropViewControllerDelegate, GACustomSelectProtocol>
@property (weak, nonatomic) IBOutlet UIButton *photoBut;
@property (strong, nonatomic) UIImage *displayImg;
@property (strong, nonatomic) UIImagePickerController *ipc;
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;

@end

@implementation HomeViewController

- (void)entryListVCWith:(UIImage *)image {
    _displayImg = image;
    [_photoBut setBackgroundImage:image forState:UIControlStateNormal];

    ListViewController *lVC = [[ListViewController alloc] initWithNibName:@"ListViewController" bundle:nil];
    lVC.img = image;
    [self.navigationController pushViewController:lVC animated:YES];
}

- (IBAction)tapPhotoAction:(id)sender {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    UIAlertAction *cameraAction = [UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self selectTakePhoto];
    }];
    [alert addAction:cameraAction];
    
    UIAlertAction *albumAction = [UIAlertAction actionWithTitle:@"从相册中选择" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self selectAlbum];
    }];
    [alert addAction:albumAction];
    
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {}];
    [alert addAction:cancelAction];
    [self presentViewController:alert animated:YES completion:nil];
}

- (void)selectTakePhoto {
    // 引用相机
    PureCamera *homec = [[PureCamera alloc] init];
    __weak typeof(self)myself = self;
    homec.fininshcapture = ^(UIImage *image){
        if (image) {
            [myself entryListVCWith:image];
        }
    } ;
    [self presentViewController:homec animated:NO completion:^{}];
}

- (void)selectAlbum {
    if (!self.ipc) {
        self.ipc = [[UIImagePickerController alloc] init];
        self.ipc.delegate = self;
        self.ipc.navigationBar.translucent = NO;
        self.ipc.edgesForExtendedLayout = UIRectEdgeNone;
        //self.ipc.allowsEditing = YES;
    }
    self.ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    [self presentViewController:self.ipc animated:YES completion:^{}];
}

#pragma mark - UIImagePickerControllerDelegate

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    // 从info取出此时摄像头的媒体类型
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
        // 获取照片的原图
        UIImage *original = [info objectForKey:UIImagePickerControllerOriginalImage];

        // 引用图片裁剪页
        TOCropViewController *cropController = [[TOCropViewController alloc] initWithImage:original aspectRatioStle:TOCropViewControllerAspectRatioOriginal];
        cropController.delegate = self;
        // [self pushViewController:cropController animated:YES];
        [picker presentViewController:cropController animated:YES completion:nil];
    } else {
        [picker dismissViewControllerAnimated:YES completion:^{}];
    }
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [picker dismissViewControllerAnimated:YES completion:^{}];
}

#pragma mark - TOCropViewControllerDelegate

- (void)cropViewController:(TOCropViewController *)cropViewController didCropToImage:(UIImage *)image withRect:(CGRect)cropRect angle:(NSInteger)angle {
    if (image) {
        //[cropViewController.navigationController popViewControllerAnimated:YES];
        [cropViewController dismissViewControllerAnimated:YES completion:nil];
        [_ipc dismissViewControllerAnimated:NO completion:^{}];
        [self entryListVCWith:image];
    }
}

- (void)cropViewController:(nonnull TOCropViewController *)cropViewController didFinishCancelled:(BOOL)cancelled {
    [cropViewController dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - 自定义图片选择器

- (IBAction)customSelectPicture:(id)sender {
    GACustomSelectPIC *custom = [[GACustomSelectPIC alloc] initWithNibName:@"GACustomSelectPIC" bundle:nil];
    custom.delegate = self;
    custom.tempLimitMax = 5;
    [self.navigationController pushViewController:custom animated:YES];
}

#pragma mark - GACustomSelectProtocol

- (void)customSelectAssets:(NSMutableArray *)assets {
    NSArray *subViews = [self.scrollView subviews];
    for (int i = 0 ; i < subViews.count ; i ++) {
        UIView *tempView = [subViews objectAtIndex:i];
        [tempView removeFromSuperview];
    }
    
    float width = self.scrollView.bounds.size.height;
    NSMutableArray *selectImages = [NSMutableArray new];
    for (int i = 0 ; i < assets.count ; i ++) {
        id tempAsset = [assets objectAtIndex:i];
        [self fetchImageWithAsset:tempAsset imageBlock:^(UIImage * _Nonnull image) {
            [selectImages addObject:image];
            //NSData *imageData = UIImageJPEGRepresentation(image, 0.5);
            UIImageView *tempIV = [UIImageView new];
            tempIV.frame = CGRectMake(i*width, 0, width, width);
            tempIV.image = image;
            tempIV.contentMode = UIViewContentModeScaleAspectFill;
            [tempIV.layer setMasksToBounds:YES];
            [self.scrollView addSubview:tempIV];
            [self.scrollView setContentSize:CGSizeMake(CGRectGetMaxX(tempIV.frame), width)];
        }];
    }
}
    
@end

列表页(ListViewController)
展示剪切后的图片,保存图片到自定义的相册
展示剪切图片示意图:

保存图片到自定义相册:

#import "ListViewController.h"
#import <Photos/Photos.h>
#import "SVProgressHUD.h"

@interface ListViewController ()

@property (weak, nonatomic) IBOutlet UIImageView *playIV;

@end

@implementation ListViewController

- (IBAction)savePictureAction:(id)sender {
    /**
    获取用户授权状态
    typedef NS_ENUM(NSInteger, PHAuthorizationStatus) {
        PHAuthorizationStatusNotDetermined = 0, // 不确定
        PHAuthorizationStatusRestricted,        // 家长控制,拒绝
        PHAuthorizationStatusDenied,            // 拒绝
        PHAuthorizationStatusAuthorized         // 授权
    } PHOTOS_AVAILABLE_IOS_TVOS_OSX(8_0, 10_0, 10_13);
    */
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    if (status == PHAuthorizationStatusNotDetermined) {
        // 如果状态是不确定的话,block中的内容会等到授权完成再调用
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            if (status == PHAuthorizationStatusAuthorized) {
                [self savePhoto];
            }
        }];
    } else if (status == PHAuthorizationStatusAuthorized) {
        [self savePhoto];
    } else {
        // 提示用户去打开授权
        [SVProgressHUD showInfoWithStatus:@"进入设置界面->找到当前应用->打开允许访问相册开关"];
    }
}

#pragma mark - 该方法获取在图库中是否已经创建该App的相册
// 该方法的作用,获取系统中所有的相册进行遍历,若是已有该相册则返回该相册,若是没有该相册则返回nil,参数为需要创建的相册名称
- (PHAssetCollection *)fetchAssetColletion:(NSString *)albumTitle {
    // 获取所有的相册
    PHFetchResult *result = [PHAssetCollection           fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    // 遍历相册数组
    for (PHAssetCollection *assetCollection in result) {
        if ([assetCollection.localizedTitle isEqualToString:albumTitle]) {
            return assetCollection;
        }
    }
    return nil;
}

#pragma mark - 保存图片的方法

- (void)savePhoto {
    // 修改系统相册用PHPhotoLibrary单例
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        // 调用判断是否已有该名称相册
        PHAssetCollection *assetCollection = [self fetchAssetColletion:@"测试相册"];
        // 创建一个操作图库的对象
        PHAssetCollectionChangeRequest *assetCollectionChangeRequest;
        if (assetCollection) {
            // 已有相册则获取该相册
            assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
        } else {
            // 没有该相册则创建自定义相册
            assetCollectionChangeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:@"测试相册"];
        }
        // 保存你需要保存的图片到自定义相册
        PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:self.playIV.image];
        // 这个block是异步执行的,使用占位图片先为图片分配一个内存,等到有图片的时候,再对内存进行赋值
        PHObjectPlaceholder *placeholder = [assetChangeRequest placeholderForCreatedAsset];
        [assetCollectionChangeRequest addAssets:@[placeholder]];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        if (error) {
             [SVProgressHUD showErrorWithStatus:@"保存失败"];
        } else {
             [SVProgressHUD showSuccessWithStatus:@"保存成功"];
        }
    }];
}

@end

自定义图片选择器(GACustomSelectPIC)
代码太多,放上效果图,详见demo...

自定义图片选择器相册列表:

自定义图片选择器图组列表:


TO:
PureCamera
iOS 自定义图片选择器 1 - PhotoKit
iOS中怎么存储照片到自定义相册

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UniApp 是一个基于 Vue.js 的跨平台开发框架,可以用于开发iOS、Android、H5等多个平台的应用程序。如果你想自定义滑动选择器,可以使用 UniApp 提供的组件和功能进行实现。 一种常见的实现方式是使用 `<picker>` 组件来创建滑动选择器。你可以在 `<template>` 中定义 `<picker>` 组件,然后在 `<script>` 中编写逻辑来处理选择器的数据和事件。 以下是一个简单的示例代码: ```html <template> <view> <picker :value="selectedValue" @change="handleChange"> <view class="picker-item" v-for="(item, index) in pickerData" :key="index"> {{ item }} </view> </picker> </view> </template> <script> export default { data() { return { pickerData: ['选项1', '选项2', '选项3'], selectedValue: 0 } }, methods: { handleChange(event) { this.selectedValue = event.mp.detail.value; // 处理选择变化的逻辑 } } } </script> <style> .picker-item { height: 50px; line-height: 50px; text-align: center; } </style> ``` 在上面的代码中,我们通过 `picker` 组件创建了一个滑动选择器,`pickerData` 数组中存放了选择器的选项数据。`selectedValue` 保存了当前选中的值。 当选择器的值发生变化时,会触发 `change` 事件,我们可以通过 `@change` 监听事件并调用 `handleChange` 方法来处理选择变化的逻辑。 在 `handleChange` 方法中,我们更新了 `selectedValue` 的值,并可以根据需要进行其他逻辑的处理。 通过这种方式,你可以自定义滑动选择器的外观和功能,根据实际需求进行调整和扩展。希望对你有所帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值