I am creating fully custom overlay for image picker controller. First stage is easy: I am get first view with record/take a shot button, which call takePicture()
method.
Next stage is change UI to "Retake" or "Use photo" which is also with my own design. "Retake" probably can be imitated by calling presentViewController
again. How should I imitate "Use photo" button?
You can easily inherit UIImagePickerController
Objective-C
@interface CameraViewController : UIImagePickerController
@property (readwrite, nonatomic) NSInteger state; // 0 - auto 1 - on 2 - off
@end
@implementation CameraViewController
- (instancetype)init {
self = [super init];
if (self) {
if (!TARGET_IPHONE_SIMULATOR) {
self.sourceType = UIImagePickerControllerSourceTypeCamera;
self.showsCameraControls = NO;
self.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
} else {
self.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
self.modalPresentationStyle = UIModalPresentationFullScreen;
self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
self.allowsEditing = NO;
self.mediaTypes = @[(NSString *)kUTTypeImage];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationChanged)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
Then override viewDidLoad
and customize UI to your needs by creating UIView
object and set it to self.cameraOverlayView
. In my example it is custom flash button.
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view = [[UIView alloc] initWithFrame:self.view.bounds];
view.backgroundColor = [UIColor clearColor];
UIButton *changeFlashButton = [UIButton buttonWithType:UIButtonTypeCustom];
changeFlashButton.frame = CGRectMake(70, 27, 40, 40);
[changeFlashButton setImage:[UIImage imageNamed:@"flash_auto"] forState:UIControlStateNormal];
self.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
changeFlashButton.showsTouchWhenHighlighted = YES;
[changeFlashButton addTarget:self action:@selector(changeFlashValue:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:changeFlashButton];
if (!TARGET_IPHONE_SIMULATOR) {
self.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
changeFlashButton.alpha = [[self class] isFlashAvailableForCameraDevice:self.cameraDevice];
self.cameraOverlayView = view;
}
}
- (void)changeFlashValue:(UIButton*)aSwitch {
if (self.state == 0) { //auto - on
self.state = 1;
[self.flashSwitch setImage:[UIImage imageNamed:@"flash_on"] forState:UIControlStateNormal];
self.cameraFlashMode = UIImagePickerControllerCameraFlashModeOn;
return;
}
if (self.state == 1) { //on - off
self.state = 2;
[self.flashSwitch setImage:[UIImage imageNamed:@"flash_off"] forState:UIControlStateNormal];
self.cameraFlashMode = UIImagePickerControllerCameraFlashModeOff;
return;
}
if (self.state == 2) { //off - auto
self.state = 0;
[self.flashSwitch setImage:[UIImage imageNamed:@"flash_auto"] forState:UIControlStateNormal];
self.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;
return;
}
}
Your controls of camera could be like this
Please pay attentions that for not showing to user "Retake" and "Use photo" buttons you need to set allowsEditing
to false
And actually the same for Swift 2.2+
class CameraViewController: UIImagePickerController {
var state: Int?
init() {
super.init(navigationBarClass: nil, toolbarClass: nil)
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS)) // any simulator
self.sourceType = .PhotoLibrary
#else
self.sourceType = .Camera
self.showsCameraControls = false
self.cameraCaptureMode = .Photo
#endif
self.modalPresentationStyle = .FullScreen
self.modalTransitionStyle = .CrossDissolve
self.allowsEditing = false
self.mediaTypes = [UIImagePickerControllerMediaType]
UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(orientationChanged), name: UIDeviceOrientationDidChangeNotification, object: nil)
}
// strange compiler requirements
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func orientationChanged() {
// update to the new orientation
}
override func viewDidLoad() {
super.viewDidLoad()
let view: UIView = UIView(frame: self.view.bounds)
view.backgroundColor = UIColor.clearColor()
var changeFlashButton: UIButton = UIButton(type: .Custom)
changeFlashButton.frame = CGRectMake(70, 27, 40, 40)
changeFlashButton.setImage(UIImage(named: "flash_auto"), forState: .Normal)
self.cameraFlashMode = .Auto
changeFlashButton.showsTouchWhenHighlighted = true
changeFlashButton.addTarget(self, action: #selector(changeFlashValue(_:)), forControlEvents: .TouchUpInside)
view.addSubview(changeFlashButton)
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS)) // any simulator
#else
self.cameraFlashMode = .Auto
changeFlashButton.alpha = UIImagePickerController.isFlashAvailableForCameraDevice(self.cameraDevice) ? 1 : 0
#endif
}
func changeFlashValue(aSwitch: UIButton) {
if self.state == 0 {
// auto - on
self.state = 1
self.flashSwitch.setImage(UIImage.imageNamed("flash_on"), forState: .Normal)
self.cameraFlashMode = .On
return
}
if self.state == 1 {
// on - off
self.state = 2
self.flashSwitch.setImage(UIImage.imageNamed("flash_off"), forState: .Normal)
self.cameraFlashMode = .Off
return
}
if self.state == 2 {
// off - auto
self.state = 0
self.flashSwitch.setImage(UIImage.imageNamed("flash_auto"), forState: .Normal)
self.cameraFlashMode = .Auto
return
}
}
}
You can imitate use photo by presenting a view controller that gives user option to edit the taken image and adding save and cancel button as well. How does that sound?