0

I'm trying to create a SwiftUI iOS app with a NavigationLink at the top level, and a TabView detail view, that uses .page, so I can swipe between tabs. And yes, I know the TabView is typically at the top level, with NavigationLink detal.

The app runs in the iOS simulator, but hangs/crashes on my iPhone.

Here is the code I want to work:

ContentView.swift

struct ContentView: View {

@State private var selection: String? = nil

var body: some View {
    NavigationView {
        VStack {
            NavigationLink(
                destination: DetailView(),
                tag: "tag1",
                selection: $selection) {
                    Text("Show Detail View")
                        .font(.largeTitle .bold())
                }
        }
    }
}

}

DetailView.swift

struct DetailView: View {

@State private var selectedTab = "one"

var body: some View {
    ZStack {
        // 3 main tabs
        TabView(selection: $selectedTab) {
            Text("Tab 1 View")
                .font(.largeTitle .bold())
                .tag("one")

            Text("Tab 2 View")
                .font(.largeTitle .bold())
                .tag("two")

            Text("Tab 3 View")
                .font(.largeTitle .bold())
                .tag("three")
        }
        // no dots
        .tabViewStyle(.page)
        // .tabViewStyle(PageTabViewStyle())
        // .id(UUID())

        VStack {
            Text("\(selectedTab)")
            Spacer()
        }
    }
}

}

A simplified DetailView also crahses in the same way:

Simplified detailView.swift

struct DetailView: View {
var body: some View {
    TabView {
        Text("Tab One")
            .font(.largeTitle .bold())
            .tag("one")

        Text("Tab Two")
            .font(.largeTitle .bold())
            .tag("two")
    }
    // no dots
    .tabViewStyle(.page)
}

}

When I run this on my iPhone, I can select the NavigationLink. it dims then hangs without rendering the detailView(). Much later, I get an error dialog, indicating the app was terminated due to a memory issue.

App runs on device if I remove the tabViewStyle modifier. Of course, it defaults to a traditional tab view with controls on the bottom of the device.

I am running Xcode 13.2.1 (13C100) on an M1 mac mini running macOS Monterey 12.2.1 (21D62). I am running on an iPhone 8 Plus running iOS 15.3.1. Xcode, by default, has an iOS Deployment Target of iOS 15.2.

Any suggestions?

SDGary
  • 434
  • 3
  • 17
  • `TabView` does not do well inside a `NavigationView` and probably worse because it is in a `ZStack`. You need to put the `TabView` in the outermost view. ["The tab bar is a global navigation control for your app, so make sure it’s always visible." - Apple](https://developer.apple.com/design/human-interface-guidelines/ios/bars/tab-bars/) you can create your own to get around all the issues you will encounter. – lorem ipsum Mar 01 '22 at 00:03
  • You can try with a picker and a switch (selected item in picker) – Ptit Xav Mar 01 '22 at 08:08
  • @Ioremipsum I agree tab view should be at the top level if it shows tabs at the bottom of the screen. I believe I should be able to be use "page" TaView elsewhere. My code was based on a [Sean Allen YouTube video](https://www.youtube.com/watch?v=0OaHzM3F9es) where he uses page tabViewStyle to create onboarding screens. I manually created a similar "page" affect with swipe gesture recognizer, but thought TabView was cleaner. My real question is: If it works in the simulator, why doesn't it work on a real device? – SDGary Mar 01 '22 at 16:56
  • @PtitXav I don't think a picker would work. I do have a custom implementation using swipe gesture recognizer and hard-coded values for x and y, but this is awkward. I was hoping for a clean TabView implementation. – SDGary Mar 01 '22 at 18:18
  • @SDGary : I added an example of what I meant. I use this because I needed a tab view inside navigation controller inside tabview. In my case, I out the picker on top – Ptit Xav Mar 01 '22 at 20:56

1 Answers1

0

Example using a Picker :

struct DetailView: View {
    @State private var selection: Tab = .tabOne
    enum Tab {
        case tabOne
        case tabTwo
    }

    var body: some View {
        TabView(selection: $selection) {
            Text("Tab One")
                .font(.largeTitle .bold())
                .tag(Tab.tabOne)
            
            Text("Tab Two")
                .font(.largeTitle .bold())
                .tag(Tab.tabTwo)
        }
        // no dots
        .tabViewStyle(.page)
        Picker("Details", selection: $selection) {
            Image(systemName: "1.circle").tag(Tab.tabOne)
            Image(systemName: "2.circle").tag(Tab.tabTwo)
        }
        .pickerStyle(.segmented)
    }
}
Ptit Xav
  • 3,006
  • 2
  • 6
  • 15
  • This code is good, but still uses the bottom of the screen for the segmented controller, which I am trying to avoid. This code also runs in the simulator, but crashes on my iPhone 8+. Does this code run on your (hopefully newer) phone? Does my original code run on your phone? Wondering if this issue is device specific... – SDGary Mar 02 '22 at 00:34