How to create a button to change the camera view in Swift?
The problem lies where you are setting the camera source.
You are setting it in viewDidAppear which will only be called when the view appears on the device. This is whenever you navigate to that view controller from another or close a presented view controller that is being presented by this one.
My suggestion would be to move the camera selection code into its own function that is called by both viewDidLoad and also whenever the changeCamera action is called.
@IBAction func changeCamera(sender: AnObject?) {
camera = !camera
reloadCamera()
}
func viewDidAppear(animated: Bool) {
// normal code
reloadCamera()
}
func reloadCamera() {
// camera loading code
captureSession = AVCaptureSession()
captureSession!.sessionPreset = AVCaptureSessionPresetPhoto
var captureDevice:AVCaptureDevice! = nil
// var backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
if (camera == false) {
let videoDevices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)
for device in videoDevices{
let device = device as AVCaptureDevice
if device.position == AVCaptureDevicePosition.Front {
captureDevice = device
break
}
}
} else {
var captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
}
var error: NSError?
var input = AVCaptureDeviceInput(device: captureDevice, error: &error)
if error == nil && captureSession!.canAddInput(input) {
captureSession!.addInput(input)
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
if captureSession!.canAddOutput(stillImageOutput) {
captureSession!.addOutput(stillImageOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer!.videoGravity = AVLayerVideoGravityResizeAspect
previewLayer!.connection?.videoOrientation = AVCaptureVideoOrientation.Portrait
previewView.layer.addSublayer(previewLayer)
captureSession!.startRunning()
}
}
Also, an additional improvement would be to use a custom enum to store which camera is currently in use rather than a Boolean. This means you can add to it later say if there was ever a third camera. This would look like:
enum CameraType {
case front
case back
}
var camera = CameraType.back
I hope this helps, apologies for omitting the full code examples, currently on an iPad but I'll update when I get to a computer.
Update
Make sure you remove the previous preview layer from the view before you change the camera.
func reloadCamera() {
captureSession?.stopRunning()
previewLayer?.removeFromSuperlayer()
// The rest of the camera loading code...
This should fix your camera freezing issue.
mindfreek
Hey there, I am a student Creative Technology. I love to fiddle around with Arduino, creating websites and I love good design. In 2015, my ambition is to learn Swift, a new coding language to make apps for the iPhone.
Updated on June 27, 2022Comments
-
mindfreek almost 2 years
I would like to know how I could change the camera view when I press a button. At the moment, I am using a boolean
var camera = false
and when I press a button, I want to change the value to true and get the other camera. But that is not working. I now have this:@IBAction func changeCamera(sender: AnyObject) { camera = true } override func viewWillAppear(animated: Bool) { captureSession = AVCaptureSession() captureSession!.sessionPreset = AVCaptureSessionPresetPhoto var captureDevice:AVCaptureDevice! = nil //var backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) if (camera == false){ let videoDevices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) for device in videoDevices{ let device = device as AVCaptureDevice if device.position == AVCaptureDevicePosition.Front { captureDevice = device break } } } else { var captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) } var error: NSError? var input = AVCaptureDeviceInput(device: captureDevice, error: &error) if error == nil && captureSession!.canAddInput(input) { captureSession!.addInput(input) stillImageOutput = AVCaptureStillImageOutput() stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] if captureSession!.canAddOutput(stillImageOutput) { captureSession!.addOutput(stillImageOutput) previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer!.videoGravity = AVLayerVideoGravityResizeAspect previewLayer!.connection?.videoOrientation = AVCaptureVideoOrientation.Portrait previewView.layer.addSublayer(previewLayer) captureSession!.startRunning() } } }
-
mindfreek about 9 yearsOooh, of course! The viewdidappear is only called once! I am very new to swift, so my apologies. Thank you so much for your awesome answer. I am going to try it out. I have never seen an Enum, so I will try it out. :)
-
Elliott Minns about 9 yearsNo need to apologise, learning is part of the fun and finding problems like this is the only way to learn :)
-
mindfreek about 9 yearsOkay, I tried it, but something goes wrong... There is not an error, but the preview screen just freezes. Could you help me? And I have no idea how to implement you enum here.
-
mindfreek about 9 yearsDear Elliot Minns. Your is almost completed. Do you have any idea why the view with the camera would freeze when I try to change the view? You would really help me a lot! An maybe even other people trying this. I have no clue and I am a beginner... :(
-
Elliott Minns about 9 yearsSorry for not responding sooner, I was out of the country. I'll have a look in the next hour and get it working for you. Will update my answer shortly.
-
Elliott Minns about 9 yearsUpdated. Let me know if there are any other issues.
-
mindfreek about 9 yearsYes! It is working! But I did it a little different: @IBAction func changeCameraAction(sender: AnyObject) { self.camera = !camera reloadCamera() println("tried to change") previewLayer!.frame = previewView.bounds } Also good right?
-
Elliott Minns about 9 yearsYep, good spot. You would also need to set the previewLayer's frame. Glad you got it solved! Sorry I wasn't about earlier to help.
-
John Doe over 8 yearsFor some reason enum doesn't work. It just gives me an error. What's going on?
-
Elliott Minns over 8 yearsThere's been changes in swift 1.2 to the way you declare enums, I shall make an update, but you need to use the keyword case
-
chengsam almost 8 yearsYou should remove the comma in enum:
enum CameraType { case Front case Back }