Как сделать вывод камеры той же переменной привязки, что и вывод PhotosPicker?
Я хочу, чтобы пользователи могли делать фотографии с помощью камеры или выбирать фотографию из своей библиотеки фотографий. Как только они выберут изображение, я хочу перевести их в режим редактирования с этим захваченным изображением. Библиотека фотографий работает отлично, потому что я могу идентифицировать выходные данные как захваченное изображение, а затем перенести эту фотографию в следующий просмотр. Я хочу сделать то же самое с выводом камеры... Как мне установить вывод камеры как «capturedImage», чтобы в режиме редактирования перемещалась только одна переменная фотографии (от CustomCameraView до UploadPostView)?
ЗагрузитьPostShell
import SwiftUI
struct UploadPostShell: View {
@Environment(\.dismiss) private var dismiss
@Binding var capturedImage: UIImage?
@StateObject var viewModel = UploadPostViewModel()
@StateObject var camera = CameraModel()
var body: some View {
VStack {
HStack {
Button {
dismiss()
} label: {
HStack {
Image("xmark")
.renderingMode(.template)
.resizable()
.frame(width: 28, height: 28)
.foregroundColor(.white)
Spacer()
}.frame(maxWidth: .infinity)
.padding(.leading, 8)
}
Spacer()
VStack (alignment: .center) {
Text("Add Post")
.font(Font.headline2)
.foregroundColor(.white)
}.frame(maxWidth: .infinity)
Spacer()
VStack {
Rectangle()
.frame(width: 28, height: 28)
.foregroundColor(.clear)
}.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity, maxHeight: 48)
if let b = Binding($capturedImage) {
UploadPostView(capturedImage: b, viewModel: viewModel)
} else {
CustomCameraView(capturedImage: $capturedImage)
}
HStack {
Spacer()
Button {
//upload post logic here
if let uiimage = capturedImage {
viewModel.uploadPost(caption: viewModel.caption, image: uiimage, rating: viewModel.rating, book: viewModel.book)
viewModel.loading = true
}
} label: {
if viewModel.loading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
} else {
Image("send-fill")
.renderingMode(.template)
.resizable()
}
}
.frame(width: 24, height: 24)
.padding()
.background(Color.accentColor)
.foregroundColor(.white)
.clipShape(Circle())
}
.padding(8)
}
.ignoresSafeArea(.keyboard, edges: .bottom)
.background(.black)
.onReceive(viewModel.$didUploadPost) { success in
if success {
dismiss()
capturedImage = nil
}
}
}
}
CustomCameraView
import SwiftUI
import PhotosUI
struct CustomCameraView: View {
@Environment(\.dismiss) private var dismiss
@Binding var capturedImage: UIImage?
@StateObject var camera = CameraModel()
var body: some View {
ZStack {
GeometryReader { proxy in
CameraView(camera: camera)
if camera.isTaken == false {
VStack (alignment: .leading) {
Spacer()
HStack {
PhotoPicker { result in
switch result {
case .success(let image):
capturedImage = image
case .failure(let error):
print(error)
capturedImage = nil
}
}
Spacer()
Button {
camera.takePic()
} label: {
Image(systemName: "circle")
.font(.system(size: 72))
.foregroundColor(.white)
}
Spacer()
Rectangle()
.foregroundColor(.clear)
.frame(width: 32, height: 28)
}
.padding()
}
}
}
.padding(.horizontal, 4)
.cornerRadius(6)
.background(.black)
}
.onAppear {
camera.checkPermissions()
}
}
}
Модель камеры
import Foundation
import AVFoundation
import SwiftUI
class CameraModel: NSObject, ObservableObject,AVCapturePhotoCaptureDelegate {
@Published var isTaken = false
@Published var session = AVCaptureSession()
@Published var alert = false
@Published var output = AVCapturePhotoOutput()
@Published var preview = AVCaptureVideoPreviewLayer()
@Published var picData = Data(count: 0)
func checkPermissions() {
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { status in
if status {
self.setupCamera()
}
}
case .denied:
return
case .authorized:
setupCamera()
return
default:
return
}
}
func setupCamera() {
if let device = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back) {
do {
self.session.beginConfiguration()
let input = try AVCaptureDeviceInput(device: device)
if self.session.canAddInput(input) {
self.session.addInput(input)
}
if self.session.canAddOutput(self.output) {
self.session.addOutput(self.output)
}
self.session.commitConfiguration()
} catch {
print(error)
}
} else {
print("camera not available")
}
}
func takePic() {
DispatchQueue.global(qos: .background).async {
self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
DispatchQueue.main.async {
withAnimation{ self.isTaken.toggle() }
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.session.stopRunning()
}
}
func reTake() {
DispatchQueue.global(qos: .background).async {
self.session.startRunning()
DispatchQueue.main.async {
withAnimation {
self.isTaken.toggle()
}
}
}
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error != nil {
return
}
print("pic taken...")
guard let imageData = photo.fileDataRepresentation() else { return }
self.picData = imageData
}
}
КамераView
import SwiftUI
import AVFoundation
struct CameraView: UIViewRepresentable {
@ObservedObject var camera : CameraModel
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: UIScreen.main.bounds)
DispatchQueue.global().async {
camera.session.startRunning()
DispatchQueue.main.async {
camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame = view.frame
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
}
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}