Sian 发表于 2015-4-21 13:09:20

iOS项目实战之自定义相机

一、基本思路
1、创建一个导航控制器,承载两个控制器:拍照、照片预览;
2、分别创建这两个控制器,由于视图均为静态视图,所以直接用xib创建即可;
3、引用AVFoundation框架,通过媒体与数据流的交互来获取图片;
4、各种封装


二、使用到的几个类及相关说明:
SAImagePickerController:继承导航控制器类,用他来创建一个自定义相机SACameraCtrl:拍照控制器,即拍照主界面,取景,摄像头切换、闪光灯开关、拍照按钮都在这个界面上展示;SAPhotoViewCtrl:照片预览控制器,即拍照后的预览界面,查看照片效果、确定使用照片或重拍;SAPreview:自定义View,拍照取景的那个视图,自定义是为了能够监听处理该视图上的事件,如对焦等。
三、基本界面预览:

四、关键代码:1、SACameraCtrl.h//
//SACameraCtrl.h
//Test
//
//Created by 余西安 on 15/4/13.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface SACameraCtrl : UIViewController

@end
2、SACameraCtrl.m//
//SACameraCtrl.m
//Test
//
//Created by 余西安 on 15/4/13.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import "SACameraCtrl.h"
#import "SAPreview.h"
#import "SAPhotoViewCtrl.h"
#import <AVFoundation/AVFoundation.h>
#import <CoreMotion/CoreMotion.h>
#define SourcePath [ pathForResource:@"SAImagePickerController.bundle" ofType:nil]

@interface SACameraCtrl () <UIAccelerometerDelegate>

// 输入流预览图层
@property (nonatomic, strong)   AVCaptureVideoPreviewLayer*previewLayer;

@property (weak, nonatomic) IBOutlet SAPreview *preview;

// AVCaptureSession对象来执行输入设备和输出设备之间的数据传递
@property (nonatomic, strong)   AVCaptureSession            *session;

// 设备输入流
@property (nonatomic, strong)   AVCaptureDeviceInput      *deviceInput;

// 照片输出流
@property (nonatomic, strong)   AVCaptureStillImageOutput   *imageOutput;

// 图片输出视图
@property (nonatomic, strong)   UIImageView   *cameraShowView;

// 摄像头数组
@property (nonatomic, strong, readonly) NSArray *devices;       // AVCaptureDevices

// 闪光灯切换按钮
@property (weak, nonatomic) IBOutlet UIButton *flashButton;


@end

@implementation SACameraCtrl

- (void)viewDidLoad
{
    ;
    // 创建交互流
    self.session = [ init];
    self.session.sessionPreset = AVCaptureSessionPresetPhoto;
   
    // 媒体输入
    AVCaptureDevice *device = ;
    ;
    self.deviceInput = ;
    if();
   
    // 媒体输出
    self.imageOutput = [ init];
    self.imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};
    AVCaptureConnection * connection = ;
    connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
    if();
   
    // 媒体预览
    self.previewLayer = ;
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    self.previewLayer.position = self.preview.center;
    ;
    [ beginGeneratingDeviceOrientationNotifications];
    ;
}


#pragma mark - 前后摄像头
- (NSArray *)devices
{
    return ;
}

- (void)viewWillAppear:(BOOL)animated
{
    ;
    self.previewLayer.frame = self.preview.layer.bounds;
    self.navigationController.navigationBar.hidden = YES;
    ;
}

- (void)viewDidAppear:(BOOL)animated
{
    ;
    [ setStatusBarHidden:YES];
}

- (void)viewWillDisappear:(BOOL)animated
{
    ;
    [ setStatusBarHidden:NO];
}

- (void)viewDidDisappear:(BOOL)animated
{
    ;
    ;
}

/// 媒体预览图层手势事件
- (void)setPreviewGesture
{
    // 注册一个手势事件来实现对焦功能
    UITapGestureRecognizer *tap = [ initWithTarget:self action:@selector(tapPreview:)];
    ;
}

/// 预览图层点击事件
- (void)tapPreview:(UITapGestureRecognizer *)gesture
{
    CGPoint point = ;
    CGPoint p = ;
    ;
    self.preview.aperture.center = point;
    ;
}

/// 对焦事件
- (void)focusAtPoint:(CGPoint)point
{
    AVCaptureDevice *device = self.deviceInput.device;
    NSError *error;
    if ( && )
    {
      if () {
            ;
            ;
            ;
      } else {
            SALog(@"Error: %@", error);
      }
    }
}

/// 摄像头切换事件
- (IBAction)switchCamera:(UIButton *)sender
{
    if (self.devices.count < 2) return;
   
    NSInteger oldIndex = ;
    NSInteger newIndex = (oldIndex + 1) % self.devices.count;
    AVCaptureDevice *newDevice = ;
    AVCaptureDeviceInput *newInput = ;
    if (newInput) {
      ;
      ;
      ;
      ;
      self.deviceInput = newInput;
      self.flashButton.hidden = !newDevice.isFlashAvailable;
    }
}

/// 取消事件
- (IBAction)cancel:(UIButton *)sender
{
    ;
}

/// 拍照事件
- (IBAction)shutter:(UIButton *)sender
{
    sender.userInteractionEnabled = NO;
    AVCaptureConnection * connection = ;
    connection.videoOrientation = AVCaptureVideoOrientationPortrait;
   
    connection.videoScaleAndCropFactor = 1.0;   // 获取流比例
    if (!connection) {
      NSLog(@"take photo failed!");
      return;
    }
   
    [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
      if (imageDataSampleBuffer == NULL) {
            return;
      }
      NSData * imageData = ;
      UIImage * image = ;
      SAPhotoViewCtrl *photoView = [ initWithImage:image];
      ;
      sender.userInteractionEnabled = YES;
    }];
}

/// 闪光灯开关按钮
- (IBAction)overTurn:(UIButton *)sender
{
    sender.tag = (sender.tag + 1) % 3;
    NSString *imageName = ;
    forState:UIControlStateNormal];
    ;
}

/// 切换闪光灯模式
- (void)setDevice:(AVCaptureDevice *)device FlashMode:(AVCaptureFlashMode)flashModel
{
    if (device.isFlashAvailable == NO) return;
    if () {
      device.flashMode = flashModel;
    }
    ;
}

@end
3、SAImagePickerController.h//
//SAImagePickerController.h
//Test
//
//Created by 余西安 on 15/4/15.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef void (^SAImagePickerComplete)(UIImage *image);

@interface SAImagePickerController : UINavigationController

@property (nonatomic, copy) SAImagePickerComplete completeBlock;

+ (instancetype)pickerComplete:(SAImagePickerComplete)complete;

@end
4、SAImagePickerController.m//
//SAImagePickerController.m
//Test
//
//Created by 余西安 on 15/4/15.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import "SAImagePickerController.h"
#import "SACameraCtrl.h"

@interface SAImagePickerController ()

@end

@implementation SAImagePickerController

+ (instancetype)pickerComplete:(SAImagePickerComplete)complete
{
    return [ initWithBlock:complete];
}

- (instancetype)initWithBlock:(SAImagePickerComplete)block
{
    if (self = ){
      if (block) self.completeBlock = block;
    }
    return self;
}

- (instancetype)init
{
    SACameraCtrl *cameraCtrl = [ init];
    if (self = ){
   
    }
    return self;
}

- (void)viewDidLoad
{
    ;
}

- (void)dealloc
{
    SALog(@"SAImagePickerController is dealloc");
}
@end
5、SAPhotoViewCtrl.h//
//SAPhotoViewCtrl.h
//Test
//
//Created by 余西安 on 15/4/14.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface SAPhotoViewCtrl : UIViewController

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

- (instancetype)initWithImage:(UIImage *)image;

@end
6、SAPhotoViewCtrl.m//
//SAPhotoViewCtrl.m
//Test
//
//Created by 余西安 on 15/4/14.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import "SAPhotoViewCtrl.h"
#import "SAImagePickerController.h"

@interface SAPhotoViewCtrl ()

@property (nonatomic, strong) UIImage *image;

@property (nonatomic, assign) NSInteger rotate;

@end

@implementation SAPhotoViewCtrl

- (instancetype)initWithImage:(UIImage *)image
{
    if (self = ){
      self.image = image;
      self.rotate = 0;
    }
    return self;
}

- (void)viewWillAppear:(BOOL)animated
{
    ;
    self.imageView.image = self.image;
    [ setStatusBarHidden:YES];
}

- (void)viewWillDisappear:(BOOL)animated
{
    ;
    [ setStatusBarHidden:NO];
}

- (void)viewDidLoad
{
    ;
}

/// 旋转图片
- (IBAction)transForm:(UIButton *)sender
{
    self.rotate ++;
    [UIView animateWithDuration:0.3 animations:^{
      self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, - M_PI_2);
    }];
}

/// 重新拍摄
- (IBAction)reShutter:(UIButton *)sender
{
    ;
}

/// 使用照片
- (IBAction)submitImage:(UIButton *)sender
{
    UIImageOrientation orientation = UIImageOrientationUp;
    switch (self.rotate % 4) {
      case 0:{
            orientation = UIImageOrientationRight;
      }break;
      case 1:{
            orientation = UIImageOrientationUp;
      }break;
      case 2:{
            orientation = UIImageOrientationLeft;
      }break;
      case 3:{
            orientation = UIImageOrientationDown;
      }break;
            
      default:break;
    }
    CGFloat scale = .scale;
    UIImage *image = [ initWithCGImage:self.image.CGImage scale:scale orientation:orientation];
    SAImagePickerController *pickerCtrl = (SAImagePickerController *)self.navigationController;
    pickerCtrl.completeBlock(image);
    [self dismissViewControllerAnimated:YES completion:^{
      ;
    }];
}

@end
7、SAPreview.h//
//SAPreview.h
//Test
//
//Created by 余西安 on 15/4/14.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface SAPreview : UIView

@property (nonatomic, strong) UIImageView   *aperture;

- (void)showAperture;

@end
8、SAPreview.m//
//SAPreview.m
//Test
//
//Created by 余西安 on 15/4/14.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import "SAPreview.h"

@implementation SAPreview

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = ){
      UIImage *image = ;
      self.aperture = [ initWithImage:image];
    }
    return self;
}

- (void)showAperture
{
    ;
    self.aperture.transform = CGAffineTransformMakeScale(2.0, 2.0);
    [UIView animateWithDuration:0.3 animations:^{
      self.aperture.transform = CGAffineTransformIdentity;
    }];
    ;
}

@end

五、基本使用一行代码搞定!    SAImagePickerController *imagePicker = [SAImagePickerControllerpickerComplete:^(UIImage *image) {
      self.imageView.image = image;
    }];
    ;
六、Demo下载**** Hidden Message *****

喵了个咪 发表于 2015-4-22 01:57:09

写得非常好

喵了个咪 发表于 2015-4-23 14:36:25

请问一下 , 你所使用的字体是什么名字呢 ?

Sian 发表于 2015-4-24 09:35:10

喵了个咪 发表于 2015-4-23 14:36
请问一下 , 你所使用的字体是什么名字呢 ?

按钮字体吗?系统自带默认字体,没有修改。

喵了个咪 发表于 2015-4-24 09:45:38

Sian 发表于 2015-4-24 09:35
按钮字体吗?系统自带默认字体,没有修改。

不是按钮字体 , 是代码字体 , 就是帖子里黑色背景下的代码字体 , 请问用的是哪个字体呢 ?

Sian 发表于 2015-4-24 09:54:14

喵了个咪 发表于 2015-4-24 09:45
不是按钮字体 , 是代码字体 , 就是帖子里黑色背景下的代码字体 , 请问用的是哪个字体呢 ?

在功能区插入表情旁边有个插入代码,选择Objective-C语言,系统会自动布局。

喵了个咪 发表于 2015-4-24 10:06:04

Sian 发表于 2015-4-24 09:54
在功能区插入表情旁边有个插入代码,选择Objective-C语言,系统会自动布局。

那请问系统用的是哪一种字体呢 ? 我想在Xcode里也用这种字体 , 因为这种字体看着挺舒服的 .

Sian 发表于 2015-4-24 13:04:16

本帖最后由 Sian 于 2015-4-24 13:15 编辑

喵了个咪 发表于 2015-4-24 10:06
那请问系统用的是哪一种字体呢 ? 我想在Xcode里也用这种字体 , 因为这种字体看着挺舒服的 .
Courier New
Consolas

喵了个咪 发表于 2015-4-24 13:13:35

Sian 发表于 2015-4-24 13:04
Courier New

非常感谢 !! {:3_48:}

Sian 发表于 2015-4-24 13:16:04

喵了个咪 发表于 2015-4-24 13:13
非常感谢 !!

Consolas
页: [1] 2
查看完整版本: iOS项目实战之自定义相机