Skip to content

[Bug] UI elements in a nested fullScreenCover disappear shortly after presentation #116

@Alenryuichi

Description

@Alenryuichi

When presenting a fullScreenCover from within another view that was also presented as a fullScreenCover, the UI elements of the second (nested)
cover disappear approximately 0.8 seconds after appearing. Only the base layer of the view (e.g., the camera preview) remains visible.

This seems to be a SwiftUI view lifecycle or rendering issue when dealing with nested modal presentations.

Steps to Reproduce

  1. Create a root view (HomeView) that presents a SessionView using .fullScreenCover.
  2. Inside the SessionView, add a button that presents a CameraView using a second, nested .fullScreenCover.
  3. The CameraView should contain a base layer (like a camera preview) and an overlay layer with UI controls (like buttons or text).
  4. Run the app and trigger the presentation of the SessionView, then trigger the presentation of the CameraView.

Expected Behavior

The CameraView is presented modally, and its UI controls should remain persistently visible and interactive on top of the camera preview layer.

Actual Behavior

The CameraView appears correctly at first, with all UI controls visible. However, after about 0.8 seconds, the entire UI overlay vanishes, leaving
only the base layer (the camera preview) visible. The controls are seemingly removed from the view hierarchy.

Code to Reproduce

Here is a minimal code example that demonstrates the issue:

 1 import SwiftUI                                                                                                                                 
 2                                                                                                                                                
 3 // 1. The Root View                                                                                                                            
 4 struct HomeView: View {                                                                                                                        
 5     @State private var showSession = false                                                                                                     
 6     var body: some View {                                                                                                                      
 7         Button("Present Session View") { showSession = true }                                                                                  
 8             .fullScreenCover(isPresented: $showSession) {                                                                                      
 9                 SessionView()                                                                                                                  
10             }                                                                                                                                  
11     }                                                                                                                                          
12 }                                                                                                                                              
13                                                                                                                                                
14 // 2. The First Modal View                                                                                                                     
15 struct SessionView: View {                                                                                                                     
16     @State private var showCamera = false                                                                                                      
17     var body: some View {                                                                                                                      
18         ZStack {                                                                                                                               
19             Color.gray.ignoresSafeArea()                                                                                                       
20             Button("Present Camera View") { showCamera = true }                                                                                
21                 .foregroundColor(.white)                                                                                                       
22         }                                                                                                                                      
23         .fullScreenCover(isPresented: $showCamera) {                                                                                           
24             CameraView()                                                                                                                       
25         }                                                                                                                                      
26     }                                                                                                                                          
27 }                                                                                                                                              
28                                                                                                                                                
29 // 3. The Nested Modal View (with the bug)                                                                                                     
30 struct CameraView: View {                                                                                                                      
31     var body: some View {                                                                                                                      
32         ZStack {                                                                                                                               
33             // Represents the camera preview layer                                                                                             
34             Color.black.ignoresSafeArea()                                                                                                      
35                                                                                                                                                
36             // This VStack contains the UI controls that disappear                                                                             
37             VStack {                                                                                                                           
38                 Text("Camera UI Controls")                                                                                                     
39                     .foregroundColor(.white)                                                                                                   
40                     .font(.title)                                                                                                              
41                                                                                                                                                
42                 Spacer().frame(height: 20)                                                                                                     
43                                                                                                                                                
44                 Image(systemName: "camera.circle.fill")                                                                                        
45                     .font(.system(size: 80))                                                                                                   
46                     .foregroundColor(.white)                                                                                                   
47             }                                                                                                                                  
48         }                                                                                                                                      
49     }                                                                                                                                          
50 }                                                                                                                                              

Potential Workaround

A similar issue reported by other developers suggests that delaying the camera view's appearance by a small amount of time can work around the
problem. This implies it might be a race condition in the SwiftUI rendering engine.

  1 struct CameraView: View {                                                                                                                      
  2     @State private var isCameraVisible = false                                                                                                 
  3                                                                                                                                                
  4     var body: some View {                                                                                                                      
  5         ZStack {                                                                                                                               
  6             Color.black.ignoresSafeArea()                                                                                                      
  7                                                                                                                                                
  8             if isCameraVisible {                                                                                                               
  9                 // The actual camera view and controls                                                                                         
 10                 VStack {                                                                                                                       
 11                     Text("Camera UI Controls")                                                                                                 
 12                         .foregroundColor(.white)                                                                                               
 13                     // ... more controls                                                                                                       
 14                 }                                                                                                                              
 15             }                                                                                                                                  
 16         }                                                                                                                                      
 17         .onAppear {                                                                                                                            
 18             DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {                                                                            
 19                 self.isCameraVisible = true                                                                                                    
 20             }                                                                                                                                  
 21         }                                                                                                                                      
 22         .onDisappear {                                                                                                                         
 23             self.isCameraVisible = false                                                                                                      
 24         }                                                                                                                                     
 25     }                                                                                                                                         
 26 }   

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions