2

I have several vertically-stacked two pairs of rectangles (Rectangle()), each of which has a Button. When the user taps a button, the user needs to be forwarded to a specific View. For instance, if they tap Alice, the user needs to be forwarded to AliceView.

enter image description here

If it's just the matter of one button, forwarding the user from the current View to another isn't a problem. Anyway, the following is what I have.

import SwiftUI

struct ContentView: View {
    @State var canAlice: Bool = false
    @State var canKim: Bool = false

    var body: some View {
        NavigationView {
            List {
                HStack(spacing: 0) {
                    // ZStack: A view that overlays its children, aligning them in both axes.
                    ZStack {
                        Rectangle().frame(width: UIScreen.screenWidth / 2.0, height: UIScreen.screenWidth / 2.0, alignment: .topLeading)
                            .foregroundColor(.orange)
                            .border(Color.yellow, width: 2)
                        Button(action: {
                            self.canAlice = true
                        }, label: {
                            Text("Alice")
                            .font(.largeTitle)
                            .background(Color.black)
                            .foregroundColor(.white)
                        })
                        NavigationLink(destination: AliceView(), isActive: $canAlice) { EmptyView() }
                    }
                    ZStack {
                        Rectangle().frame(width: UIScreen.screenWidth / 2.0, height: UIScreen.screenWidth / 2.0, alignment: .topLeading)
                            .foregroundColor(.orange)
                            .border(Color.yellow, width: 2)
                        Button(action: {
                            self.canKim = true
                        }, label: {
                            Text("Kim")
                                .font(.largeTitle)
                                .background(Color.black)
                                .foregroundColor(.white)
                        })
                        NavigationLink(destination: KimView(), isActive: $canKim) { EmptyView() }
                    }
                }.listRowInsets(EdgeInsets())

                HStack(spacing: 0) {
                    ...
                    ...
                    ...
                }.listRowInsets(EdgeInsets())

                HStack(spacing: 0) {
                    ...
                    ...
                    ...
                }.listRowInsets(EdgeInsets())

                HStack(spacing: 0) {
                    ...
                    ...
                    ...
                }.listRowInsets(EdgeInsets())
            }
            .edgesIgnoringSafeArea(.all)
            .statusBar(hidden: true)
        }
    }
}

Now, if I tap the Alice button, the current View transitions to AliceView, comes back to the current View and then transitions to KimView. How can I have multiple buttons within a single View and forward the user to respective Views? I'm new to SwiftUI. Thanks.

UPDATE

import SwiftUI

struct ContentView: View {
    @State private var selection: Int? = 0

    var body: some View {
        NavigationView {
            List {
                HStack(spacing: 0) {
                    // ZStack: A view that overlays its children, aligning them in both axes.
                    ZStack {
                        Rectangle().frame(width: UIScreen.screenWidth / 2.0, height: UIScreen.screenWidth / 2.0, alignment: .topLeading)
                            .foregroundColor(.orange)
                            .border(Color.yellow, width: 2)
                        Button(action: {
                            self.selection = 1
                        }, label: {
                            Text("Alice")
                                .font(.largeTitle)
                                .background(Color.black)
                                .foregroundColor(.white)
                        })
                        NavigationLink(destination: AliceView(), tag: 1, selection: self.$selection) { EmptyView() }
                    }
                    ZStack {
                        Rectangle().frame(width: UIScreen.screenWidth / 2.0, height: UIScreen.screenWidth / 2.0, alignment: .topLeading)
                            .foregroundColor(.orange)
                            .border(Color.yellow, width: 2)
                        Button(action: {
                            self.selection = 2
                        }, label: {
                            Text("Kim")
                                .font(.largeTitle)
                                .background(Color.black)
                                .foregroundColor(.white)
                        })
                        NavigationLink(destination: KimView(), tag: 2, selection: self.$selection) { EmptyView() }
                    }
                }.listRowInsets(EdgeInsets())

                HStack(spacing: 0) {
                    ...
                    ...
                    ...
                }.listRowInsets(EdgeInsets())

                HStack(spacing: 0) {
                    ...
                    ...
                    ...
                }.listRowInsets(EdgeInsets())

                HStack(spacing: 0) {
                    ...
                    ...
                    ...
                }.listRowInsets(EdgeInsets())
            }
            .edgesIgnoringSafeArea(.all)
            .statusBar(hidden: true)
        }
    }
}

Now, when I tap Alice or Kim, I won't transition to another view and then bounce back to the initial view. Whether I tap Alice or Kim, I transition to AliceView.

El Tomato
  • 6,479
  • 6
  • 46
  • 75
  • The solution for similar scenario was provided in [SwiftUI MVVM Coordinator/Router/NavigationLink](https://stackoverflow.com/a/61188788/12299030) – Asperi Jun 13 '20 at 03:23
  • @Asperi I've made some changes according to your answer. Now, whether I tap Alice or Kim, I end up transitioning to KimView. – El Tomato Jun 13 '20 at 06:08

2 Answers2

1

Here is a solution (by approach referenced in comment). Tested with Xcode 11.4 / iOS 13.4

enter image description here

Button style to hide a link:

struct LinkButtonStyle<D: View>: ButtonStyle {
    let destination: D
    @Binding var isActive: Bool

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .background(NavigationLink(destination: self.destination, isActive: $isActive) { EmptyView() })
    }
}

and an example of modified cell

ZStack {
    Rectangle().frame(width: UIScreen.screenWidth / 2.0, height: UIScreen.screenWidth / 2.0, alignment: .topLeading)
        .foregroundColor(.orange)
        .border(Color.yellow, width: 2)
    Button(action: {
        self.canAlice = true
    }, label: {
        Text("Alice")
        .font(.largeTitle)
        .background(Color.black)
        .foregroundColor(.white)
    }).buttonStyle(LinkButtonStyle(destination: AliceView(), isActive: $canAlice))
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
0

You could achieve this using a single Bool for isActice parameter and a single NavigationLink. Also need to add a destination parameter outside the body. And set the destination in the button action. Here's an example:

struct ContentView: View {

    @State var showNextView = false
    var destination = GeorgeView()

    var body: some View {
        NavigationView {
            List {
                HStack(spacing: 0) {
                    NavigationLink(destination: destination, isActive: $showNextView) { EmptyView() }
                    // Rest of your implementation...
                        Button(action: {
                            self.destination = KimView()
                            self.showNextView = true
                        }, label: {
                            Text("Kim")
                            .font(.largeTitle)
                            .background(Color.black)
                            .foregroundColor(.white)
                        })
                }
            }
        }
    }
}
Frankenstein
  • 15,732
  • 4
  • 22
  • 47
  • Thanks. I get multiple errors at the line of self.destination = KimView(). 1. Cannot assign to property: 'self' is immutable 2. Cannot assign value of type 'KimView' to type 'GeorgeView' – El Tomato Jun 13 '20 at 01:57