Search code examples
iosxcodeswiftuiios16swiftui-tabview

SwiftUI TabView loses selection when container size changes given safe area ignored


I need to ignore the safe area of a TabView so that ScrollViews within the different pages will show their scrollable content outside the safe area.

When the container's safe area changes, for example when the keyboard is shown, the view will be redrawn and it's selection state lost.

2022-10-10 17:18:13.762064+0800 SafeArea[73226:7824972] The behavior of the UICollectionViewFlowLayout is not defined because:
2022-10-10 17:18:13.762259+0800 SafeArea[73226:7824972] the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
2022-10-10 17:18:13.762567+0800 SafeArea[73226:7824972] The relevant UICollectionViewFlowLayout instance is <_TtC7SwiftUIP33_8825076C2763A50452A210CBE1FA4AF012PagingLayout: 0x7f8509c0a680>, and it is attached to <_TtC7SwiftUIP33_8825076C2763A50452A210CBE1FA4AF020PagingCollectionView: 0x7f850b037400; baseClass = UICollectionView; frame = (0 0; 393 612.667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x6000009fa550>; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x6000007d4ac0>; contentOffset: {0, 0}; contentSize: {786, 726.33333333333337}; adjustedContentInset: {0, 0, 21.267423644046971, 0}; layout: <_TtC7SwiftUIP33_8825076C2763A50452A210CBE1FA4AF012PagingLayout: 0x7f8509c0a680>; dataSource: <_TtC7SwiftUIP33_8825076C2763A50452A210CBE1FA4AF011Coordinator: 0x60000359c5a0>>.
2022-10-10 17:18:13.763934+0800 SafeArea[73226:7824972] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.

enter image description here

Code to reproduce:

import SwiftUI

struct ContentView: View {
    
    @State var selection = 0
    
    var body: some View {
        VStack {
            Text("An app")
            TabView(selection: $selection) {
                ScrollView {
                    TextField("First textfield", text: .constant(""))
                }
                .background(.blue)
                .tag(0)
                
                ScrollView {
                    TextField("Second textfield", text: .constant(""))
                }
                .background(.red)
                .tag(1)
            }
            .tabViewStyle(.page)
            .ignoresSafeArea(.container, edges: .bottom)
        }
    }
}

Simply removing the .ignoresSafeArea(.container, edges: .bottom) stops the view's selection from being lost but also loses the ScrollView's ability to show it's content outside of the safe area.

Am I doing something wrong or is this an issue with SwiftUI? I didn't notice it before building against iOS 16 with Xcode 14 so has something change or is something broken :D.


Solution

  • Apple have confirmed this was a regression in Xcode 14 which has now been fixed in Xcode 14.1.

    https://feedbackassistant.apple.com/feedback/11684856