[iOS] custom picture selector

This article is due to a question asked during the interview this summer. Have you customized photo selector? So I take the time to check the data and write a simple demo here.
1. Write a "custom picture selector".
2. The tool is used to cut the picture after getting the picture“ PureCamera".
3. Save the edited picture to a custom album.
4. Finally, multi selection function is added for the custom picture selector.

demo diagram:

Home view controller
Home page diagram:

#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;


@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:@"Photograph" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self selectTakePhoto];
    [alert addAction:cameraAction];
    UIAlertAction *albumAction = [UIAlertAction actionWithTitle:@"Choose from album" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self selectAlbum];
    [alert addAction:albumAction];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {}];
    [alert addAction:cancelAction];
    [self presentViewController:alert animated:YES completion:nil];

- (void)selectTakePhoto {
    // Citing camera
    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 {
    // Remove the media type of the camera at this time from info
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
        // Get the original picture of the photo
        UIImage *original = [info objectForKey:UIImagePickerControllerOriginalImage];

        // Reference picture crop page
        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 - custom picture selector

- (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)];

List page (ListViewController)
Display the cut pictures and save them to the customized album
Show the cut picture:

To save a picture to a custom Album:

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

@interface ListViewController ()

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


@implementation ListViewController

- (IBAction)savePictureAction:(id)sender {
    Get user authorization status
    typedef NS_ENUM(NSInteger, PHAuthorizationStatus) {
        PHAuthorizationStatusNotDetermined = 0, // Uncertain
        PHAuthorizationStatusRestricted,        // Parental control, decline
        PHAuthorizationStatusDenied,            // refuse
        PHAuthorizationStatusAuthorized         // To grant authorization
    } PHOTOS_AVAILABLE_IOS_TVOS_OSX(8_0, 10_0, 10_13);
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    if (status == PHAuthorizationStatusNotDetermined) {
        // If the status is uncertain, the content in the block will be called after the authorization is completed
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            if (status == PHAuthorizationStatusAuthorized) {
                [self savePhoto];
    } else if (status == PHAuthorizationStatusAuthorized) {
        [self savePhoto];
    } else {
        // Prompt user to open authorization
        [SVProgressHUD showInfoWithStatus:@"Enter the setting interface->Find current app->Turn on the allow access to album switch"];

#pragma mark - this method gets whether the album of the App has been created in the gallery
// The function of this method is to obtain all albums in the system for traversal. If there is an existing album, the album will be returned. If there is no album, the nil will be returned. The parameter is the name of the album to be created
- (PHAssetCollection *)fetchAssetColletion:(NSString *)albumTitle {
    // Get all albums
    PHFetchResult *result = [PHAssetCollection           fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    // Traverse album array
    for (PHAssetCollection *assetCollection in result) {
        if ([assetCollection.localizedTitle isEqualToString:albumTitle]) {
            return assetCollection;
    return nil;

#pragma mark - how to save pictures

- (void)savePhoto {
    // Single example of PHPhotoLibrary for modifying system album
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        // Call to determine whether the album with this name already exists
        PHAssetCollection *assetCollection = [self fetchAssetColletion:@"Test albums"];
        // Create an object to operate the library
        PHAssetCollectionChangeRequest *assetCollectionChangeRequest;
        if (assetCollection) {
            // Get an existing album
            assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
        } else {
            // Create a custom album without the album
            assetCollectionChangeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:@"Test albums"];
        // Save the pictures you need to save to a custom album
        PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:self.playIV.image];
        // This block is executed asynchronously. Use the occupying image to allocate a memory for the image first, and then assign the memory when there is a picture
        PHObjectPlaceholder *placeholder = [assetChangeRequest placeholderForCreatedAsset];
        [assetCollectionChangeRequest addAssets:@[placeholder]];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        if (error) {
             [SVProgressHUD showErrorWithStatus:@"Save failed"];
        } else {
             [SVProgressHUD showSuccessWithStatus:@"Save successfully"];


There are too many codes. Put the renderings. See demo for details

Custom picture selector album list:

Custom picture picker group list:

iOS custom picture selector 1 - PhotoKit
How to store photos to a custom album in iOS

Keywords: Mobile iOS

Added by cheeks2k on Thu, 12 Dec 2019 22:24:05 +0200