如何使 VStack 可点击以在 SwiftUI 中显示警报
How to make a VStack Clickable to show alert in SwiftUI
我有一个带有图像和文本的 VStack,我需要将其设置为可点击,以便向用户显示和提醒。我尝试了 onTapGesture 方法,但我能够打印语句,但没有显示警报。
是否有任何替代方法来获得解决方案?
我已经添加了整个 swift 文件供您参考
代码
@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
}
我已将您的代码简化为最基本的部分。您实际上不需要添加点击手势,您可以将整个元素(例如 VStack
)包装在 Button
中并从那里处理触发警报。重要的一点是,当用户点击 Alert
上的确定时,请记住将 showConnectionAlert
设置回 false。将它包裹在 Button
中的副作用是内部的所有内容都将以淡色呈现。这就是我将 .foregroundCololor()
应用于 VStack
的原因(对于某些图像,您可能还必须添加 .renderingMode(.original)
修饰符):
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 }))
}
}
}
为了使空容器可点击(例如 Spacer()),您应该使用 .contentShape(Rectangle())
修饰符:
VStack(spacing: 4) {
Image(systemName: "antenna.radiowaves.left.and.right")
Text("Connected")
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
print("The whole VStack is tappable now!")
}
我有一个带有图像和文本的 VStack,我需要将其设置为可点击,以便向用户显示和提醒。我尝试了 onTapGesture 方法,但我能够打印语句,但没有显示警报。
是否有任何替代方法来获得解决方案?
我已经添加了整个 swift 文件供您参考
代码
@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
}
我已将您的代码简化为最基本的部分。您实际上不需要添加点击手势,您可以将整个元素(例如 VStack
)包装在 Button
中并从那里处理触发警报。重要的一点是,当用户点击 Alert
上的确定时,请记住将 showConnectionAlert
设置回 false。将它包裹在 Button
中的副作用是内部的所有内容都将以淡色呈现。这就是我将 .foregroundCololor()
应用于 VStack
的原因(对于某些图像,您可能还必须添加 .renderingMode(.original)
修饰符):
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 }))
}
}
}
为了使空容器可点击(例如 Spacer()),您应该使用 .contentShape(Rectangle())
修饰符:
VStack(spacing: 4) {
Image(systemName: "antenna.radiowaves.left.and.right")
Text("Connected")
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
print("The whole VStack is tappable now!")
}