SwiftUI中打开全屏设置视图时停止相机运行的优雅解决方案
Hey there! I see the issue you're facing—when you present the settings view via fullScreenCover, the camera stays active (that green privacy indicator doesn't go away) because the underlying AVCaptureSession in your CustomCameraController never stops running. Let's fix this with a straightforward, maintainable solution.
Why This Happens
The CameraPreviewRepresentable (and its attached CustomCameraController) isn't destroyed when you present the settings view—it's just hidden beneath the full-screen cover. Since the captureSession was started in viewDidLoad, it continues running in the background, keeping the camera active.
Step-by-Step Solution
1. Add Session Control Methods to CustomCameraController
First, let's give our camera controller explicit methods to stop and restart the capture session. We'll also make sure these operations run on the main thread (required for AVFoundation interactions):
import UIKit import Combine import AVFoundation class CustomCameraController: UIViewController { // ... (keep your existing properties and methods) func stopRunningCaptureSession() { DispatchQueue.main.async { if self.captureSession.isRunning { self.captureSession.stopRunning() } } } func restartCaptureSession() { DispatchQueue.main.async { if !self.captureSession.isRunning { self.captureSession.startRunning() } } } // ... (keep your existing setup methods) }
2. Listen to Settings View Presentation State
In your CameraView, we'll listen for changes to the didTapSettings binding. When the settings view is presented, we'll stop the camera session; when it's dismissed, we'll restart it:
struct CameraView: View { @State private var didTapCapture = false @State private var didTapSettings = false let cameraController: CustomCameraController @ObservedObject var cameraViewModel: CameraViewModel var body: some View { VStack { // ... (keep your existing camera preview and button layout) } .fullScreenCover(isPresented: $didTapSettings) { VStack(spacing: 30) { Text("Settings View ⚙️") .font(.largeTitle) Button("OK") { didTapSettings.toggle() } } } .onChange(of: didTapSettings) { isSettingsPresented in if isSettingsPresented { // Stop camera when settings view appears cameraController.stopRunningCaptureSession() } else { // Restart camera when settings view is dismissed cameraController.restartCaptureSession() } } } }
3. Optional: Add Safety Checks (For Robustness)
If you want to make sure the session can safely restart (e.g., if the user revoked camera permissions while in settings), you can add a check in restartCaptureSession:
func restartCaptureSession() { DispatchQueue.main.async { guard AVCaptureDevice.authorizationStatus(for: .video) == .authorized else { // Handle permission denial here (e.g., show alert to guide user to settings) return } if !self.captureSession.isRunning { self.captureSession.startRunning() } } }
How This Works
- When
didTapSettingsbecomestrue(settings view is presented), we callstopRunningCaptureSession()—this halts the camera session, turning off the green privacy indicator immediately. - When
didTapSettingsbecomesfalse(settings view is dismissed), we callrestartCaptureSession()—this resumes the camera session so the user can take photos again without any extra steps.
This approach keeps camera logic encapsulated where it belongs (in CustomCameraController) and uses SwiftUI's native state observation to trigger actions at the right moments—clean, maintainable, and user-friendly.
内容的提问来源于stack exchange,提问作者ViOS

