SwiftUIを使ったカメラの実装で、フロントカメラとバックカメラの切り替えについての記事です。
他サイトにもいろんな方法は乗っていると思いますが。自分のメモように残しておこうと思います。
トグルボタンの設定
カメラのアイコンのついたボタンです。これを押すとカメラが切り替わるようにしたいと思います。
Button(action: {
camera.switchCamera()
}) {
Image(systemName: "arrow.triangle.2.circlepath.camera")
.font(.largeTitle)
.padding()
}
.background(Color.white.opacity(0.7))
.clipShape(Circle())
機能
前回の記事に以下コードを追記すればOKです。
func switchCamera() {
currentCameraPosition = currentCameraPosition == .front ? .back : .front
updateCameraPosition()
}
全コード
特に出し惜しみする必要もないので、ここまでのコードを下に全て載せます。
コピペしてこれが動かなかったら、この記事がもう古くなったことでしょう。
import SwiftUI
import AVFoundation
struct CameraView: View {
@StateObject var camera = CameraViewModel()
var body: some View {
ZStack {
CameraControll(camera: camera)
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Button(action: {
camera.switchCamera()
}) {
Image(systemName: "arrow.triangle.2.circlepath.camera")
.font(.largeTitle)
.padding()
}
.background(Color.white.opacity(0.7))
.clipShape(Circle())
}
}
}
}
struct CameraControll: UIViewRepresentable {
@ObservedObject var camera: CameraViewModel
func makeUIView(context: Context) -> UIView { camera }
func updateUIView(_ uiView: UIViewType, context: Context) {}
}
class CameraViewModel: UIView, ObservableObject {
var previewLayer: AVCaptureVideoPreviewLayer?
var currentCameraPosition: AVCaptureDevice.Position = .front
var session = AVCaptureSession()
override func layoutSubviews() {
super.layoutSubviews()
_ = initCaptureSession
previewLayer?.frame = bounds
fixCameraOrientation()
}
lazy var initCaptureSession: Void = {
updateCameraPosition()
}()
private func updateCameraPosition() {
session.inputs.forEach { session.removeInput($0) }
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera],
mediaType: .video,
position: .unspecified)
.devices.first(where: { $0.position == currentCameraPosition }),
let input = try? AVCaptureDeviceInput(device: device) else { return }
session.addInput(input)
if previewLayer == nil {
let previewLayer = AVCaptureVideoPreviewLayer(session: session)
layer.insertSublayer(previewLayer, at: 0)
self.previewLayer = previewLayer
}
session.startRunning()
}
func switchCamera() {
currentCameraPosition = currentCameraPosition == .front ? .back : .front
updateCameraPosition()
}
private func fixCameraOrientation() {
let rotation: CGFloat = CGFloat(getDeviceOrientation().rawValue) * 90
previewLayer?.transform = CATransform3DMakeRotation(rotation / 180 * CGFloat.pi, 0, 0, 1)
}
private func getDeviceOrientation() -> Orientation {
guard let interfaceOrientation = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.windowScene?.interfaceOrientation else {
return .right
}
switch interfaceOrientation {
case .landscapeLeft:
return .left
case .landscapeRight:
return .right
case .portrait:
return .down
case .portraitUpsideDown:
return .up
default:
return .right
}
}
}
enum Orientation: Int {
case right = -1, down = 0, left = 1, up = 2
}
#Preview {
CameraView()
}
コメントを残す