简体   繁体   中英

How to make a VStack Clickable to show alert in SwiftUI

I have a VStack with image and a text, I need to make it clickable so I can show and alert to the user. I have tried onTapGesture method but I'm able to print the statement but alert is not showing up.

Is there any alternate way to get the solution?

I have added the whole swift file for your reference

Code

@State private var hasOneConnected: Bool = false
@State private var showConnectionAlert = false

private var connectionAlert: Alert {
    Alert.init(title: Text("Oops!"), message: Text("There is an error."), dismissButton: .default(Text("OK")))
}
var body: some View {
    VStack(alignment: .center, spacing: 0) {

        // MARK: - Header
        VStack(alignment: .center, spacing: 0) {
            Spacer().frame(height: 55)
            HStack(alignment: .center, spacing: 25) {
                Spacer()
                Image("Logo")
                Spacer(minLength: 5)
                Text("Zone Control")
                    .foregroundColor(.white)
                Spacer()
            }
            Spacer()
        }
        .frame(height: 100, alignment: .center)
        .background(
            LinearGradient(
                gradient: Gradient(colors: [Color.Heat.primary, Color.Heat.primary.opacity(0.8), Color.Heat.primary.opacity(0.5)]),
                startPoint: .top, endPoint: .bottom
            )
        )
        // MARK: - Menu Bar
        HStack(alignment: .center, spacing: 10) {
            Spacer().frame(maxWidth: 20)

            HStack(alignment: .center, spacing: 10) {
                Image("batteryModule")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 8)
                Text("Pod Status")
                    .font(.caption)
                    .foregroundColor(.white)
            }

            Spacer()

            VStack(alignment: .center, spacing: 4) {
                Image(self.hasConnected ? "bluetoothConnected" : "bluetoothNotConnected")
                Text(self.hasConnected ? "Connected" : "Disconnected")
                    .font(.caption)
                    .foregroundColor(.white)
            }
            .frame(width: 80)

            VStack(alignment: .center, spacing: 4) {
                Image("batteryStatus")
                Text("\(self.batteryLevel)%")
                    .font(.caption)
                    .foregroundColor(.white)
            }
            .frame(width: 60)

            Spacer().frame(maxWidth: 10)
        }
        .padding()
        .background(Color.black)

    }

    .statusBar(hidden: true)
    .edgesIgnoringSafeArea(.all)
    .onAppear(perform: {
        UserDefaults.standard.set(true, forKey: "onboarding")
        self.update()
    })
        .onReceive(self.skiinBLE.objectWillChange) { _ in
            self.update()
    }

}

func update() {
    self.hasOneConnected = self.topLayer.cbPeripheral?.state != .disconnected
    self.batteryLevel = self.topLayer.moduleInformation?.batteryLevel.rawValue ?? 0

}

I have simplified your code to just bare essentials. You don't really need to add a tap gesture, you can wrap the whole element (eg a VStack ) in a Button and handle triggering the alert from there. Important bit is to remember to set showConnectionAlert back to false when the user taps OK on the Alert . The side effect of wrapping it in a Button is that everything inside will be rendered in the tint colour. That's why I have applied .foregroundCololor() to the VStack (with some images you might also have to add .renderingMode(.original) modifier):

struct ContentView: View {

    @State private var showConnectionAlert = false

    var body: some View {
        Button(action: { self.showConnectionAlert = true }) {
            VStack(spacing: 4) {
                Image(systemName: "antenna.radiowaves.left.and.right")
                Text("Connected")
            }   .foregroundColor(.primary)
        }
            .alert(isPresented: $showConnectionAlert) {
                    Alert(title: Text("Nice"),
                          message: Text("The alert is showing!"),
                          dismissButton: Alert.Button.default(Text("OK"),
                                                              action: { self.showConnectionAlert = false }))
        }
    }
}

For making empty containers tappable (for example Spacer()), you should use .contentShape(Rectangle()) modifier:

VStack(spacing: 4) {
  Image(systemName: "antenna.radiowaves.left.and.right")
  Text("Connected")
  Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
  print("The whole VStack is tappable now!")
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM