Animating the slide in of a form causes visual glitches on landscape iPhones with notches

Viewed 141

I'm have a button to make a settings menu slide in from the left in SwiftUI, everything was working great until I switched from the iPhone SE to the iPhone 11 simulator!

Form slide in glitch

The problem is that using a ZStack to have form overlaid over the interface, and then animating the appearance of that form causes there to be visual glitches where the elements contained inside the rows clip outside the cell width. This clipping occurs at the start of the animation and stays in place once the animation is done.

This does not happen if the animation is disabled, the device is portrait, or for devices that do not have a notch.

Causing the view to redraw by rotating the device or using the "NO ANIM" button fixes the glitch until you animated it again.

Changing the transition to .opacity works in this case, but .opacity has the same issue in some view structures as well...

I have tried structuring it in a different way where the menu is always there but just offset so it is off the screen, again same problem.

I assume this is a bug in SwiftUI, and so have submitted a bug report. But does anyone have a workaround?

Xcode version = 11.5, iOS version = 13.5

struct ContentView: View {
   @State var menuOpen = true
   @State var bar = false

   var body: some View {
      ZStack(alignment: .leading) {
         HStack {
            Spacer()
            VStack {
            Button(action: {
               withAnimation(.default) {
                  self.menuOpen.toggle()
               }
            }) {
               Text("MENU ANIM")
            }
               Button(action: {
                     self.menuOpen.toggle()
               }) {
                  Text("MENU NO ANIM")
               }
            }
         }
         if menuOpen {
            Form {
               Section(header: Text("SETTINGS")) {
                  Toggle(isOn: $bar) { Text("Toggle") }
                  Toggle(isOn: $bar) { Text("Toggle")  }
               }
            }
            .frame(width:300, alignment: .topLeading)
               .transition(.move(edge: .leading))
         }
      }
      .frame( maxWidth: .infinity, maxHeight: .infinity)
   }
}
1 Answers

Explicit row insets solves the issue (tested with Xcode 11.4 / iOS 13.4)

demo

Form {
   Section(header: Text("SETTINGS")) {
      Toggle(isOn: $bar) { Text("Toggle") }
      Toggle(isOn: $bar) { Text("Toggle")  }
   }
   .listRowInsets(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)) // << here !!
}
.frame(width:300, alignment: .topLeading)
.transition(.move(edge: .leading))
Related