demo:https://download.csdn.net/download/u012881779/10739412
之前做电商平台图片搜索时写的一个拍照购的demo。
示意图:
[iOS]拍照购
自定义相机:
[iOS]拍照购

#import <UIKit/UIKit.h>
#import "ResultViewController.h"

typedef void(^customSelectImageViewBlock)(UIImage *selectImage);

@interface GACustomCameraViewController : UIViewController

@property (nonatomic, strong) customSelectImageViewBlock selectImage;

@end

#import "GACustomCameraViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>

@interface GACustomCameraViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate>

@property (weak, nonatomic) IBOutlet UIButton *theFlashBut;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *statusHighConstraint;
@property (strong, nonatomic) AVCaptureSession *session;
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
@property (strong, nonatomic) AVCaptureDevice *device;
@property (strong, nonatomic) AVCaptureDeviceInput *deviceInput;
@property (strong, nonatomic) AVCaptureStillImageOutput *imageOutput;
@property (strong, nonatomic) AVCaptureConnection *connection;

@end

@implementation GACustomCameraViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 判断相机 是否可以使用
    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        NSLog(@"sorry, no camera or camera is unavailable.");
        return;
    }
    // 设置相机
    [self initCameraSettings];
    // 当前闪光灯状态
    if (self.device.flashMode == AVCaptureFlashModeOff) {
        _theFlashBut.selected = NO;
    } else {
        _theFlashBut.selected = YES;
    }
    // 状态栏高度
    _statusHighConstraint.constant = [[UIApplication sharedApplication] statusBarFrame].size.height;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:YES];
    if (self.session) {
        [self.session startRunning];
    }
    [self shatusViewHidden:NO];
    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:YES];
    if (self.session) {
        [self.session stopRunning];
    }
    // [self shatusViewHidden:NO];
    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
}

// 状态栏显示/隐藏
- (void)shatusViewHidden:(BOOL)result {
    UIView *statusView = [[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"] valueForKey:@"statusBar"];
    statusView.hidden = result;
}

// 初始化相机
- (void)initCameraSettings {
    NSError *error;
    // 创建会话层
    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    // 初始化session
    self.session = [[AVCaptureSession alloc] init];
    if ([self.session canSetSessionPreset:AVCaptureSessionPresetPhoto]) {
        self.session.sessionPreset = AVCaptureSessionPresetPhoto;
    }
    // 初始化输入设备
    self.deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
    // 初始化照片输出对象
    self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
    [self.imageOutput setOutputSettings:outputSettings];
    // 判断输入输出设备是否可用
    if ([self.session canAddInput:self.deviceInput]) {
        [self.session addInput:self.deviceInput];
    }
    if ([self.session canAddOutput:self.imageOutput]) {
        [self.session addOutput:self.imageOutput];
    }
    // 初始化预览图层
    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
    /** 设置图层的填充样式
     AVLayerVideoGravityResize, // 非均匀模式。两个维度完全填充至整个视图区域
     AVLayerVideoGravityResizeAspect, // 等比例填充,直到一个维度到达区域边界
     AVLayerVideoGravityResizeAspectFill, // 等比例填充,直到填充满整个视图区域,其中一个维度的部分区域会被裁剪
     */
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    self.previewLayer.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
    [self.view.layer insertSublayer:self.previewLayer atIndex:0];
}

// 返回
- (IBAction)returnAction:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)returnWithImage:(UIImage *)image {
    /*
    // 在首页跳转
    [self returnAction:nil];
    if (self.selectImage) {
        self.selectImage(image);
    }*/
    // 在自定义相机跳转
    [self entryRsultVCWithImage:image];
}

- (void)entryRsultVCWithImage:(UIImage *)image {
    ResultViewController *result = [[ResultViewController alloc] initWithNibName:@"ResultViewController" bundle:nil];
    result.originalImage = image;
    [self presentViewController:result animated:YES completion:nil];
}

// 闪光灯
- (IBAction)theFlashAction:(id)sender {
    AVCaptureFlashMode mode;
    UIButton *tempBut = (UIButton *)sender;
    if (tempBut.isSelected) {
        tempBut.selected = NO;
        mode = AVCaptureFlashModeOff;
    } else {
        tempBut.selected = YES;
        mode = AVCaptureFlashModeOn;
    }
    if ([self.device isFlashModeSupported:mode]) {
        [self.session beginConfiguration];
        [self.device lockForConfiguration:nil];
        [self.device setFlashMode:mode]; // 这行代码就要放在这个顺序的位置否则会崩溃
        [self.device unlockForConfiguration];
        [self.session commitConfiguration];
        [self.session startRunning];
    }
}

// 拍照
- (IBAction)takePhotoAction:(id)sender {
    self.connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    [self.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
    [self.imageOutput captureStillImageAsynchronouslyFromConnection:self.connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [UIImage imageWithData:jpegData];
        [self returnWithImage:image];
    }];
}

// 前置/后置摄像头
- (IBAction)frontOrRearCameraAction:(id)sender {
    [UIView beginAnimations:@"animation" context:nil];
    [UIView setAnimationDuration:.5f];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
    [UIView commitAnimations];
    
    NSArray *inputs = self.session.inputs;
    for ( AVCaptureDeviceInput *input in inputs ) {
        AVCaptureDevice *device = input.device;
        if ( [device hasMediaType:AVMediaTypeVideo] ) {
            AVCaptureDevicePosition position = device.position;
            AVCaptureDevice *newCamera = nil;
            AVCaptureDeviceInput *newInput = nil;
            if (position == AVCaptureDevicePositionFront) {
                newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
            } else {
                newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
            }
            newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
            [self.session beginConfiguration];
            [self.session removeInput:input];
            [self.session addInput:newInput];
            [self.session commitConfiguration];
            break;
        }
    }
}

// 相机状态
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position {
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for ( AVCaptureDevice *device in devices ) {
        if ( device.position == position ) {
            return device;
        }
    }
    return nil;
}

// 打开相册
- (IBAction)openAlbumAction:(id)sender {
    UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
    pickerController.delegate = self;
    pickerController.navigationBar.translucent = NO;
    pickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    pickerController.edgesForExtendedLayout = UIRectEdgeNone;
    [self presentViewController:pickerController animated:YES completion:nil];
}

#pragma mark - 从相册选择图片后操作

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    // 获取拍照的图像
    // UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    // 获取图片裁剪的图
    // UIImage *edit = [info objectForKey:UIImagePickerControllerEditedImage];
    // 获取照片的原图
    UIImage *original = [info objectForKey:UIImagePickerControllerOriginalImage];
    [picker dismissViewControllerAnimated:NO completion:^{
        [self returnWithImage:original];
    }];
}

#pragma mark - 取消操作时调用

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

@end

结果展示页:
[iOS]拍照购

#import <UIKit/UIKit.h>

@interface ResultViewController : UIViewController

@property (strong, nonatomic) UIImage *originalImage;

@end

#import "ResultViewController.h"
#import "YBPictureCutterView.h"

static float const LIMIT_SV_BOTTOM = 120.0;     // scrollView底部最大移动范围
static float const LIMIT_DRAG_DISTANCE = 44.0;  // 拖动超过响应范围后自动滚动到约束位置
static float const LIMIT_CO_TOP = 100.0;        // 约束内容视图顶部
static float const LIMIT_CO_BOTTOM = 200.0;     // 约束图片视图底部

@interface ResultViewController () <YBPictureCutterViewDataSource, YBPictureCutterViewDelegate, UIGestureRecognizerDelegate>

@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (weak, nonatomic) IBOutlet UIView *contentTitleBGView;
@property (weak, nonatomic) IBOutlet UIImageView *tempShowIV;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *ivBottomConstraint;    // 图片区域的bottom约束
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentTopConstraint;  // 内容区域的top约束
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *scrollViewBottomConstraint; // 图片区域sv的bottom约束
@property (strong, nonatomic) YBPictureCutterView *cutterView;
@property (strong, nonatomic) UIImageView *showImageView;
@property (assign, nonatomic) CGPoint startPoint;   // 开始拖动时的起始点
@property (assign, nonatomic) CGFloat startTopY;    // 开始拖动时的内容区域top约束
@property (assign, nonatomic) CGFloat startSCBottomY;   // 开始拖动时图片区域Bottom约束
@property (assign, nonatomic) CGFloat startSCOffSetY;   // 开始拖动时图片区域offset.y

@end

@implementation ResultViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _contentTopConstraint.constant = LIMIT_CO_TOP;
    _ivBottomConstraint.constant = LIMIT_CO_BOTTOM;
    _scrollViewBottomConstraint.constant = LIMIT_SV_BOTTOM;
    // UIView部分倒圆角
    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:_contentTitleBGView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(10, 10)];
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.frame = _contentTitleBGView.bounds;
    maskLayer.path = maskPath.CGPath;
    _contentTitleBGView.layer.mask = maskLayer;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self updateScrollViewWithDev:0];
    [_scrollView addSubview:self.showImageView];
    self.showImageView.image = _originalImage;
    [self.showImageView addSubview:self.cutterView];
    self.showImageView.userInteractionEnabled = YES;
    [self adaptationSafeAreaWith:_scrollView useArea:1];
}

- (void)updateScrollViewWithDev:(float)dev {
    float hbw = _originalImage.size.height/(float)_originalImage.size.width;
    float newWidth = [UIScreen mainScreen].bounds.size.width;
    float newHeight = newWidth*hbw;
    float devY = 0;
    BOOL result = NO;
    if (_scrollView.frame.size.height > newHeight) {
        devY = (_scrollView.frame.size.height - newHeight)/2.0;
    } else {
        result = YES;
    }
    [_scrollView setContentSize:CGSizeMake(newWidth, newHeight)];
    self.showImageView.frame = CGRectMake(0, devY, newWidth, newHeight);
    if (result) {
        CGPoint oldOffset = _scrollView.contentOffset;
        oldOffset.y = _startSCOffSetY - dev;
        CGFloat jgHeight = _scrollView.contentSize.height-_scrollView.frame.size.height;
        if (oldOffset.y < 0) {
            oldOffset.y = 0;
        } else if (oldOffset.y > jgHeight) {
            oldOffset.y = jgHeight;
        }
        [_scrollView setContentOffset:oldOffset];
    }
}

- (UIImageView *)showImageView {
    if (!_showImageView) {
        _showImageView = [UIImageView new];
        [_showImageView setContentMode:UIViewContentModeScaleToFill];
    }
    return _showImageView;
}

- (YBPictureCutterView *)cutterView {
    if (!_cutterView) {
        _cutterView = [[YBPictureCutterView alloc] init];
        _cutterView.dataSource = self;
        _cutterView.delegate = self;
    }
    _cutterView.frame = _showImageView.bounds;
    return _cutterView;
}

#pragma mark - pictureCutterView dataSource & delegate

- (UIImage *)imageForPictureCutterView:(YBPictureCutterView *)cutterView {
    return _showImageView.image;
}

- (void)pictureCutterView:(YBPictureCutterView *)cutterView didClippedImage:(UIImage *)image {
    NSLog(@"%@", NSStringFromCGSize(image.size));
    _tempShowIV.image = image;
}


- (IBAction)returnAction:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

/**
 * 适配iPhone X的安全区域
 * isUse = 1 表示使用安全区域
 * isUse = 0 表示不使用安全区域
 */
- (void)adaptationSafeAreaWith:(UIScrollView *)sv useArea:(NSInteger)isUse {
#ifdef __IPHONE_11_0
    if ([sv respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
        if (isUse) {
            if (@available(iOS 11.0, *)) {
                sv.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
                if ([[sv class] isSubclassOfClass:[UITableView class]]) {
                    UITableView *tv = (UITableView *)sv;
                    [tv setInsetsContentViewsToSafeArea:NO];
                }
            } else {
                // Fallback on earlier versions
            }
        } else {
            if (@available(iOS 11.0, *)) {
                sv.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAlways;
            } else {
                // Fallback on earlier versions
            }
        }
    }
#endif
}

#pragma mark - PanGestureRecognizer手势

- (IBAction)contentViewPanGesture:(UIPanGestureRecognizer *)gestureRecognizer {
    UIView *tempView = gestureRecognizer.view;
    if (tempView.tag == 567) {
        CGPoint tempPoint = [gestureRecognizer locationInView:self.view];
        // 图片ScrollView底部约束移动范围
        CGFloat scMaxMoveRange = LIMIT_SV_BOTTOM;
        // 图片ScrollView移动范围/内容View移动范围
        CGFloat bl = scMaxMoveRange/(float)([UIScreen mainScreen].bounds.size.height - LIMIT_CO_TOP - LIMIT_CO_BOTTOM);
        CGFloat scrHeight = [UIScreen mainScreen].bounds.size.height;
        CGFloat devY = tempPoint.y-_startPoint.y;
        CGFloat newY = _startTopY + devY;
        if (newY >= LIMIT_CO_TOP) {
            if (newY <= (scrHeight - LIMIT_CO_BOTTOM)) {
                _contentTopConstraint.constant = newY;
                _scrollViewBottomConstraint.constant = _startSCBottomY - bl*devY;
                [self updateScrollViewWithDev:bl*devY];
            } else {
                [self toBottomLocationWithConstant:0 Dev:0];
                return;
            }
        } else {
            [self toTopLocationWithConstant:scMaxMoveRange Dev:0];
            return;
        }
        // 判断是否拖动结束
        if (gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled) {
            CGFloat responseRange = LIMIT_DRAG_DISTANCE;
            BOOL result = NO;
            if (devY > 0) {
                if (devY >= responseRange) {
                    [self toBottomLocationWithConstant:0 Dev:bl*devY];
                } else {
                    result = YES;
                }
            } else if (devY < 0) {
                if (devY <= (0 - responseRange)) {
                    [self toTopLocationWithConstant:scMaxMoveRange Dev:bl*devY];
                } else {
                    result = YES;
                }
            }
            if (result) {
                [self toOldLocationWithConstant:self.startSCBottomY Dev:bl*devY];
            }
        }
    }
}

// 滚动到底部位置
- (void)toBottomLocationWithConstant:(float)constant Dev:(float)dev {
    self.scrollViewBottomConstraint.constant = constant;
    [self.view layoutIfNeeded];
    [UIView animateWithDuration:0.3 animations:^{
        self.contentTopConstraint.constant = [UIScreen mainScreen].bounds.size.height - LIMIT_CO_BOTTOM;
        [self updateScrollViewWithDev:dev];
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        self.collectionView.scrollEnabled = NO;
    }];
}

// 滚动到顶部位置
- (void)toTopLocationWithConstant:(float)constant Dev:(float)dev {
    self.scrollViewBottomConstraint.constant = constant;
    [self.view layoutIfNeeded];
    [UIView animateWithDuration:0.3 animations:^{
        self.contentTopConstraint.constant = LIMIT_CO_TOP;
        [self updateScrollViewWithDev:dev];
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        self.collectionView.scrollEnabled = YES;
    }];
}

// 滚动回到原位置
- (void)toOldLocationWithConstant:(float)constant Dev:(float)dev {
    self.scrollViewBottomConstraint.constant = constant;
    [self.view layoutIfNeeded];
    [UIView animateWithDuration:0.3 animations:^{
        self.contentTopConstraint.constant = self.startTopY;
        [self updateScrollViewWithDev:dev];
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        if (self.startTopY == LIMIT_CO_TOP) {
            self.collectionView.scrollEnabled = YES;
        }
    }];
}

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    UIView *tempView = gestureRecognizer.view;
    if (tempView.tag == 567) {
        _startPoint = [gestureRecognizer locationInView:self.view];
        _startSCBottomY = _scrollViewBottomConstraint.constant;
        _startSCOffSetY = _scrollView.contentOffset.y;
        _startTopY = _contentTopConstraint.constant;
        CGFloat tempLimitBottom = [UIScreen mainScreen].bounds.size.height - LIMIT_CO_BOTTOM;
        if (_startTopY != LIMIT_CO_TOP && _startTopY != tempLimitBottom) {
            if (_startTopY-LIMIT_CO_TOP < tempLimitBottom-_startTopY) {
                _startTopY = LIMIT_CO_TOP;
            } else {
                _startTopY = tempLimitBottom;
            }
        }
    }
    return YES;
}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.tag == 2000) {
        CGPoint offset = scrollView.contentOffset;
        if (offset.y <= 0) {
            offset.y = 0;
            scrollView.contentOffset = offset;
            self.collectionView.scrollEnabled = NO;
        } else {

        }
    }
}

@end

 

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-04-25
  • 2021-08-10
  • 2022-12-23
  • 2021-09-08
猜你喜欢
  • 2022-01-14
  • 2021-08-21
  • 2021-10-15
  • 2022-01-10
  • 2021-12-27
  • 2022-02-13
  • 2022-01-20
相关资源
相似解决方案