skip to Main Content

I’m running into an issue that stems from having a button in one action sheet that opens another action sheet attached to a different subview of a ZStack. I’m not sure why, but sometimes the second action sheet appears, and sometimes it doesn’t. I thought wrapping the state change code inside a DispatchQueue.main.async { } would run the code on the main thread and thus fix this issue, but SOMETIMES, when the button ‘Show AS2’ is pressed, the second action sheet does not appear. Any help with this issue is much appreciated.

I have something that looks like this:

I have a normal view with 2 state variables:

@State var showActionSheet1 = false
@State var showActionSheet2 = false

The body of the view looks like this:

ZStack {
  HStack {
    Spacer()
    Button(action: {
      showActionSheet1 = true
    }, label: {

    }).actionSheet(isPresented: $showActionSheet1) {
      ActionSheet(
        title: Text("Select an option"),
        buttons: [
          .cancel(),
          .default(Text("Tap to Do Something")) {
            print("Do something")
          },
          .default(Text("Show AS2")) {
            //showing the other action sheet
            DispatchQueue.main.async {
              showActionSheet2 = true
            }
          }
        ]
      )
    }
  }
  VStack {
    Spacer()
    HStack {
      Spacer()
      Text("Element")
    }
  }.actionSheet(isPresented: $showActionSheet2) {
      ActionSheet(
        title: Text("Select an option"),
        buttons: [
          .cancel(),
          .default(Text("Tap to Do Something on second sheet")) {
            print("Do something")
          },
          .default(Text("tap to do something on second sheet 2")) {
            //showing the other action sheet
            print("Do something 2")
          }
        ]
      )
    }
}

2

Answers


  1. It can be only one ActionSheet on a screen and while one is closed it needs time (due to animation) to disappear from screen. In that time second ActionSheet cannot be shown.

    The solution is to delay a bit activation of second sheet. (Actually in real end-user flow it is rarely needed but it is better to take such specifics into account)

          .default(Text("Show AS2")) {
            //showing the other action sheet
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {  // << here !!
              showActionSheet2 = true
            }
          }
    
    Login or Signup to reply.
  2. @Asperi is right. There must be only one .actionSheet per View.

    You could implement this by using the ternary operator.

    Xcode 14.1 example:

    struct ActionSheetExample {
    
        @State var showActionSheet: Bool
        @State var isSheetTypeOne: Bool
    
        var body: some View {
            ZStack {
                VStack(spacing: 10) {
                    Button("Main Sheet") {
                        isSheetTypeOne = true
                        showActionSheet = true
                    }
                }
                .actionSheet(isPresented: $showActionSheet) {
                    isSheetTypeOne ? ActionSheet(
                        title: Text("Select environment"),
                        buttons: [
                            .default(Text("Production")) {
                                isSheetTypeOne = false
                                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                                    showActionSheet = true
                                }
                            },
                            .default(Text("Staging")) {
                                // Perform some action
                            },
                        ]
                    ) : ActionSheet(
                        title: Text("Select your login type"),
                        buttons: [
                            .default(Text("Normal Login")) {
                                // Perform some action
                            },
                            .default(Text("Onboarding")) {
                                // Perform some action
                            }
                        ]
                    )
                }
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search