UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: SOLVED: Show Sheet With Button Based On Value

Forums > SwiftUI

This has only just come up in Xcode 12 and iOS 14. I have an enum that determines which sheet to display. However, when I choose an option it does not update the view to show the correct view within the sheet.

As an example, the code below will show the first view as it is the default value. However, if the third view is selected from the buttons, the first view will display regardless. The console says the enum has updated, but it appears the view is not updated. Strangely, the issue occurs until you choose any other options than the first one you select...

Just an Xcode 12 bug or something I've done? Same issue occurs in both the simulator and on device.

Any help is greatly appreciated.

struct ContentView: View
{
    @State var showView : ViewDecider = .first
    @State var showSheet : Bool = false

    var body: some View
    {
        VStack(spacing: 30)
        {
            Button("Show First")
            {
                showView = .first
                showSheet.toggle()
                print(showView)
            }

            Button("Show Second")
            {
                showView = .second
                showSheet.toggle()
                print(showView)
            }

            Button("Show Third")
            {
                showView = .third
                showSheet.toggle()
                print(showView)
            }
        }.sheet(isPresented: $showSheet, content:
        {
            if showView == .first
            {
                Text("First")
            }
            else if showView == .second
            {
                Text("Second")
            }
            else
            {
                Text("Third")
            }
        })
    }
}

enum ViewDecider
{
    case first
    case second
    case third
}

I've applied the Hacking With Swift sample to show a second example..

struct ContentView: View
{
    @State var loadingState : LoadingState = .loading
    @State var showSheet : Bool = false

    enum LoadingState
    {
        case loading, success, failed
    }

    var body: some View
    {
        VStack(spacing: 30)
        {
            Button("Loading")
            {
                loadingState = .loading
                showSheet.toggle()
                print(loadingState)
            }

            Button("Success")
            {
                loadingState = .success
                showSheet.toggle()
                print(loadingState)
            }

            Button("Failed")
            {
                loadingState = .failed
                showSheet.toggle()
                print(loadingState)
            }
        }.sheet(isPresented: $showSheet, content:
        {
            Group
            {
                if loadingState == .loading {
                    LoadingView()
                } else if loadingState == .success {
                    SuccessView()
                } else if loadingState == .failed {
                    FailedView()
                }
            }
        })
    }
}

struct LoadingView: View {
    var body: some View {
        Text("Loading...")
    }
}

struct SuccessView: View {
    var body: some View {
        Text("Success!")
    }
}

struct FailedView: View {
    var body: some View {
        Text("Failed.")
    }
}

Same issue with a Bool, when you tap on Success you get the Loading view. Unless you tap on Loading then Success you continue to see the loading view.

struct ContentView: View
{
    @State var loading : Bool = true
    @State var showSheet : Bool = false

    var body: some View
    {
        VStack(spacing: 30)
        {
            Button("Loading")
            {
                loading = true
                showSheet.toggle()
                print(loading)
            }

            Button("Success")
            {
                loading = false
                showSheet.toggle()
                print(loading)
            }

        }.sheet(isPresented: $showSheet, content:
        {
            Group
            {
                if loading
                {
                    LoadingView()
                } else
                {
                    SuccessView()
                }
            }
        })
    }
}

struct LoadingView: View {
    var body: some View {
        Text("Loading...")
    }
}

struct SuccessView: View {
    var body: some View {
        Text("Success!")
    }
}

3      

Try a different initializer for sheet. Make showView an Optional without initial value. The behaviour seems to have changed with iOS 14 but I found no documentation of this. You don't need the showSheet bool variable with this approach.

.sheet(item: $showView, onDismiss: { showView = nil }) { item in
      switch item {
      case .first:
          Text("first")
      case .second:
          Text("second")
      case .third:
          Text("third")
          }

3      

Thank you! I have zero idea why this has changed, assuming it is intentional. One less variable isn't a bad thing I suppose. The solution has broken the cancel button to the mail sheet via a UIRepresentable but I'll have a play. Thanks again.

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.