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
}
To show an alert, create some Boolean state that determines whether the alert should be visible, then attach that to an alert() modifier along with all the buttons you want to show in the alert. All buttons dismiss the alert when tapped, so you can provide an empty action for simple dismissal.
Using stacks in SwiftUI allows you to arrange multiple views into a single coherent view with certain properties. HStack allows to arrange its child views in a horizontal line. VStack allows to arrange its child views in a vertical line, and ZStack allows to overlap its child views on top of each other.
A view that arranges its children in a vertical line.
A stack is a collection of SwiftUI views that are grouped together. You can use 3 kinds of stacks with SwiftUI: VStack, a vertical stack, which shows views in a top-to-bottom list. HStack, a horizontal stack, which shows views in a left-to-right list. ZStack, a depth-based stack, which shows views in a back-to-front ...
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 (e.g. 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!")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With