iOS - AVFoundation - 自定義相機界面

Snip20170312_4.png

使用系統(tǒng)提供的UIImagePickerController可以實現(xiàn)基本的拍照和錄制視頻的功能秧荆,但是很多時候從UI那邊拿到的設計圖都是和系統(tǒng)的不一樣的祠墅,我們需要自定義相機的界面。

大概思路

1.根據(jù)UI的設計圖响谓,把基本的界面先搭建出來(感覺是廢話⊙o⊙)损合。
2.使用AVFoundation必須的幾個東西 -device,input娘纷,output塌忽,session,connection失驶,previewLayer
3.按鈕點擊之后的邏輯處理 - 閃光燈土居,前后攝像頭的切換等

主要的內容就是AVFoundation的使用

//1.獲取device(audio,video)
//2.根據(jù)device創(chuàng)建input
//3.創(chuàng)建輸出output(下面圖片是輸出的方式,共7種)
//4.創(chuàng)建全局的會話session擦耀,并且把輸入和輸出都添加到session中棉圈,統(tǒng)一管理
//5.如果需要實時的顯示,就用AVCaptureVideoPreviewLayer預覽圖層來顯示

圖片還是視頻區(qū)別在于輸出output的不同

14881125871512.jpg

直接上代碼

//

#import "CustomCameraVC.h"
#import "UIControl+BlocksKit.h"
#import "UIView+YGYAdd.h"
#import <AVFoundation/AVFoundation.h>

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface CustomCameraVC () <AVCapturePhotoCaptureDelegate>

//UI界面搭建
@property (nonatomic, strong) UIView *topView;
@property (nonatomic, strong) UIButton *closeButton;
@property (nonatomic, strong) UIButton *flashModeButton;
@property (nonatomic, strong) UIButton *cameraButton;

@property (nonatomic, strong) UIView *middleView;

@property (nonatomic, strong) UIView *bottomView;
@property (nonatomic, strong) UIButton *albumButton;
@property (nonatomic, strong) UIButton *takePhotoButton;
@property (nonatomic, strong) UIButton *musicButton;

//自定義相機(AVFoundation)
@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureDevice *device;
@property (nonatomic, strong) AVCaptureDeviceInput *input;
@property (nonatomic, strong) AVCaptureStillImageOutput *output;
@property (nonatomic, strong) AVCaptureConnection *connection;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *preViewLayer;

@property (nonatomic, strong) NSArray *flashModelArray;
@property (nonatomic, assign) NSInteger flashModel;
@end

@implementation CustomCameraVC

- (void)viewDidLoad {
    [super viewDidLoad];
    _flashModelArray = @[@"icon-pz-sgd-gb",@"icon-pz-sgd-zd",@"icon-pz-sgd"];
    _flashModel = 0;
    
    [self setupUI];
    [self customCamera];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [_session startRunning];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [_session stopRunning];
}


- (void)setupUI {
    //頂部UI
    [self makeTopUI];
    //中間預覽圖層
    [self makeMiddleUI];
    //底部UI
    [self makeBottomUI];
}

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    //---top
    
    _topView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight*0.2);
    _closeButton.frame = CGRectMake(0, 0, 50, 50);
    _closeButton.centerY = _topView.centerY;
    
    _flashModeButton.frame = CGRectMake(0, 0, 50, 50);
    _flashModeButton.center = _topView.center;
    
    _cameraButton.frame = CGRectMake(0, 0, 50, 50);
    _cameraButton.centerY = _topView.centerY;
    _cameraButton.right = _topView.right;
    
    
    //---middle
    
    _middleView.frame = CGRectMake(0, CGRectGetMaxY(_topView.frame), kScreenWidth, kScreenHeight*0.6);
    _preViewLayer.frame = _middleView.bounds;
    
    //---bottom
    
    _bottomView.frame = CGRectMake(0, CGRectGetMaxY(_middleView.frame), kScreenWidth, kScreenHeight*0.2);
    _albumButton.frame = CGRectMake(0, 0, 50, 50);
//    _albumButton.centerY = _bottomView.centerY;//不能這么寫眷蜓,超出父控件
    _albumButton.centerY = _bottomView.height*0.5;
    
    _takePhotoButton.frame = CGRectMake(0, 0, 50, 50);
//    _takePhotoButton.center = _bottomView.center;
    _takePhotoButton.center = CGPointMake(_bottomView.width*0.5, _bottomView.height*0.5);
    
    _musicButton.frame = CGRectMake(0, 0, 50, 50);
//    _musicButton.centerY = _bottomView.centerY;
    _musicButton.centerY = _bottomView.height*0.5;
    _musicButton.right = _bottomView.right;
    
}

- (void)makeTopUI {
    _topView = [[UIView alloc] init];
    _topView.backgroundColor = [UIColor grayColor];
    
    
    _closeButton = [[UIButton alloc] init];
    [_closeButton setImage:[UIImage imageNamed:@"icon-pz-exit"] forState:UIControlStateNormal];
    [_closeButton bk_addEventHandler:^(id  _Nonnull sender) {
        //關閉控制器
        [self dismissViewControllerAnimated:YES completion:nil];
    } forControlEvents:UIControlEventTouchUpInside];
    
    
    _flashModeButton = [[UIButton alloc] init];
    [_flashModeButton setImage:[UIImage imageNamed:@"icon-pz-sgd"] forState:UIControlStateNormal];
    [_flashModeButton bk_addEventHandler:^(id  _Nonnull sender) {
        //切換閃光燈的模式
        //    icon-pz-sgd-zd
        [self changeFlashModel];
    } forControlEvents:UIControlEventTouchUpInside];
    
    _cameraButton = [[UIButton alloc] init];
    [_cameraButton setImage:[UIImage imageNamed:@"icon-pz-fz"] forState:UIControlStateNormal];
    [_cameraButton bk_addEventHandler:^(id  _Nonnull sender) {
        //切換前后攝像頭
        [self changeCamera];
    } forControlEvents:UIControlEventTouchUpInside];
    
    
    [_topView addSubview:_closeButton];
    [_topView addSubview:_flashModeButton];
    [_topView addSubview:_cameraButton];
    
    [self.view addSubview:_topView];
    
}

- (void)makeMiddleUI {
    _middleView = [[UIView alloc] init];
    [self.view addSubview:_middleView];
}

- (void)makeBottomUI {
    _bottomView = [[UIView alloc] init];
    _bottomView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:_bottomView];
    
    _albumButton = [[UIButton alloc] init];
    [_albumButton setImage:[UIImage imageNamed:@"icon-pz-TP"] forState:UIControlStateNormal];
    [_albumButton bk_addEventHandler:^(id  _Nonnull sender) {
        //從相冊選取
    } forControlEvents:UIControlEventTouchUpInside];
    
    _takePhotoButton = [[UIButton alloc] init];
    [_takePhotoButton setImage:[UIImage imageNamed:@"icon-pz-pz"] forState:UIControlStateNormal];
    [_takePhotoButton bk_addEventHandler:^(id  _Nonnull sender) {
        [self takePhoto];
    } forControlEvents:UIControlEventTouchUpInside];
    
    _musicButton = [[UIButton alloc] init];
    [_musicButton setImage:[UIImage imageNamed:@"icon-pz-music"] forState:UIControlStateNormal];
    [_musicButton bk_addEventHandler:^(id  _Nonnull sender) {
        //音頻選擇
    } forControlEvents:UIControlEventTouchUpInside];
    
    [_bottomView addSubview:_albumButton];
    [_bottomView addSubview:_takePhotoButton];
    [_bottomView addSubview:_musicButton];
    
}

- (void)customCamera {
    _session = [[AVCaptureSession alloc] init];
    
    _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    NSError *error = nil;
    _input = [[AVCaptureDeviceInput alloc] initWithDevice:_device error:&error];

    if (error) {
        NSLog(@"創(chuàng)建輸入設備失敗 -- %@",error);
        return;
    }
    
    AVCaptureStillImageOutput *output = [[AVCaptureStillImageOutput alloc] init];
    _output = output;
//    _connection = [output connectionWithMediaType:AVMediaTypeVideo];//千萬不要在這里獲取分瘾,輸入和輸出都沒有加入session,所以獲取的connection始終是nil

    if ([_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [_session setSessionPreset:AVCaptureSessionPreset1280x720];
    }
    
    if ([_session canAddInput:_input]) {
        [_session addInput:_input];
    }else {
        NSLog(@"添加輸入設備失敗");
        return;
    }
    
    if ([_session canAddOutput:output]) {
        [_session addOutput:output];
    }else {
        NSLog(@"添加輸出設備失敗");
        return;
    }
    
    
    AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill ;
    _preViewLayer = layer;
    [_middleView.layer addSublayer:layer];
}

- (void)takePhoto {//拍照就是從輸出(output)從connection中獲取一張圖片
    _connection = [_output connectionWithMediaType:AVMediaTypeVideo];
    [_output captureStillImageAsynchronouslyFromConnection:_connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if (imageDataSampleBuffer) {
            NSData *data = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [UIImage imageWithData:data];
            //顯示還是存儲到相冊的邏輯
            NSLog(@"%@",image);
        }
    }];
}

- (void)changeCamera {//切換攝像頭 - input改變
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (int i = 0; i < devices.count; ++i) {
        AVCaptureDevice *device = devices[i];
        
        if (_device.position != device.position) {
            _device = device;
            break;//找到就不要再找吁系,邏輯就不對了
        }
    }
    NSError *error = nil;
    AVCaptureDeviceInput *newInput = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];

    if (error) {
        NSLog(@"創(chuàng)建輸入設備失敗 -- %@",error);
        return;
    }
    [_session beginConfiguration];
    [_session removeInput:_input];
    if ([_session canAddInput:newInput]) {
        [_session addInput:newInput];
        _input = newInput;
    }
    
    [_session commitConfiguration];
    
}

- (void)changeFlashModel {
    //FlashModel是輸入設備的屬性,不需要使用session
    
    if ([_device hasFlash]) {//必須判斷德召,否則前置攝像頭的時候就會奔潰
        [_device lockForConfiguration:nil];
        [_device setFlashMode:_flashModel++ % 3];//注意:閃關燈不是手電筒,只有拍的時候才會亮 
        [_device unlockForConfiguration];
        [_flashModeButton setImage:[UIImage imageNamed:_flashModelArray[_flashModel % 3]] forState:UIControlStateNormal];
    }
    
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末汽纤,一起剝皮案震驚了整個濱河市上岗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蕴坪,老刑警劉巖肴掷,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異背传,居然都是意外死亡呆瞻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門径玖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痴脾,“玉大人,你說我怎么就攤上這事梳星≡蘩担” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵丰泊,是天一觀的道長薯定。 經常有香客問我始绍,道長瞳购,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任亏推,我火速辦了婚禮学赛,結果婚禮上,老公的妹妹穿的比我還像新娘吞杭。我一直安慰自己盏浇,他們只是感情好,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布芽狗。 她就那樣靜靜地躺著绢掰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滴劲,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天攻晒,我揣著相機與錄音,去河邊找鬼班挖。 笑死鲁捏,一個胖子當著我的面吹牛,可吹牛的內容都是我干的萧芙。 我是一名探鬼主播给梅,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼双揪!你這毒婦竟也來了动羽?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盟榴,失蹤者是張志新(化名)和其女友劉穎曹质,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體擎场,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡羽德,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了迅办。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宅静。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖站欺,靈堂內的尸體忽然破棺而出姨夹,到底是詐尸還是另有隱情,我是刑警寧澤矾策,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布磷账,位于F島的核電站,受9級特大地震影響贾虽,放射性物質發(fā)生泄漏逃糟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一蓬豁、第九天 我趴在偏房一處隱蔽的房頂上張望绰咽。 院中可真熱鬧,春花似錦地粪、人聲如沸取募。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玩敏。三九已至斗忌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旺聚,已是汗流浹背飞蹂。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留翻屈,地道東北人陈哑。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像伸眶,于是被迫代替她去往敵國和親惊窖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容