一个视图中的多个警报只能在 swiftui 中始终有效
Multiple Alerts in one view can only the last alert works always in swiftui
我有两个警报,如果布尔值为真,则调用它们。
Alert - 1 - 如果蓝牙状态有任何问题而不是供电时调用 on.This 直接从 swift 包调用命名为 BLE。代码片段如下。
Alert - 2 - 当你想取消配对外围设备给用户两个 options.Unpair 或保持在同一页面时调用。
问题:
这两个警报似乎都工作正常,但如果它们未放置在同一视图中。当我将警报放在同一视图中时,最后显示的警报从上到下顺序调用。
OS 读取第一个警报,但仅在调用时激活第二个警报。
有没有办法让这两个警报在被调用时都起作用。
我参考了以下解决方案,但我得到了相同的结果。
and Solution 2
有 2 个代码片段
1.主要应用
import SwiftUI
import BLE
struct Dashboard: View {
@EnvironmentObject var BLE: BLE
@State private var showUnpairAlert: Bool = false
private var topLayer: HeatPeripheral {
self.BLE.peripherals.baseLayer.top
}
var body: some View {
VStack(alignment: .center, spacing: 0) {
// MARK: - Menu Bar
VStack(alignment: .center, spacing: 4) {
Button(action: {
print("Unpair tapped!")
self.showUnpairAlert = true
}) {
HStack {
Text("Unpair")
.fontWeight(.bold)
.font(.body)
}
.frame(minWidth: 85, minHeight: 35)
.cornerRadius(30)
}
}
}
.onAppear(perform: {
self.BLE.update()
})
// Alert 1 - It is called if it meets one of the cases and returns the alert
// It is presented in the function centralManagerDidUpdateState
.alert(isPresented: $BLE.showStateAlert, content: { () -> Alert in
let state = self.BLE.centralManager!.state
var message = ""
switch state {
case .unknown:
message = "Bluetooth state is unknown"
case .resetting:
message = "Bluetooth is resetting..."
case .unsupported:
message = "This device doesn't have a bluetooth radio."
case .unauthorized:
message = "Turn On Bluetooth In The Settings App to Allow Battery to Connect to App."
case .poweredOff:
message = "Turn On Bluetooth to Allow Battery to Connect to App."
break
@unknown default:
break
}
return Alert(title: Text("Bluetooth is \(self.BLE.getStateString())"), message: Text(message), dismissButton: .default(Text("OK")))
})
// Alert 2 - It is called when you tap the unpair button
.alert(isPresented: $showUnpairAlert) {
Alert(title: Text("Unpair from \(checkForDeviceInformation())"), message: Text("*Your peripheral command will stay on."), primaryButton: .destructive(Text("Unpair")) {
self.unpairAndSetDefaultDeviceInformation()
}, secondaryButton: .cancel())
}
}
func unpairAndSetDefaultDeviceInformation() {
defaults.set(defaultDeviceinformation, forKey: Keys.deviceInformation)
disconnectPeripheral()
print("Pod unpaired and view changed to Onboarding")
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.async {
self.activateLink = true
}
}
func disconnectPeripheral(){
if skiinBLE.peripherals.baseLayer.top.cbPeripheral != nil {
self.skiinBLE.disconnectPeripheral()
}
}
}
2。 BLE 包
import SwiftUI
import Combine
import CoreBluetooth
public class BLE: NSObject, ObservableObject {
public var centralManager: CBCentralManager? = nil
public let baseLayerServices = "XXXXXXXXXXXXXXX"
let defaults = UserDefaults.standard
@Published public var showStateAlert: Bool = false
public func start() {
self.centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
self.centralManager?.delegate = self
}
public func getStateString() -> String {
guard let state = self.centralManager?.state else { return String() }
switch state {
case .unknown:
return "Unknown"
case .resetting:
return "Resetting"
case .unsupported:
return "Unsupported"
case .unauthorized:
return "Unauthorized"
case .poweredOff:
return "Powered Off"
case .poweredOn:
return "Powered On"
@unknown default:
return String()
}
}
}
extension BLE: CBCentralManagerDelegate {
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("state: \(self.getStateString())")
if central.state == .poweredOn {
self.showStateAlert = false
if let connectedPeripherals = self.centralManager?.retrieveConnectedPeripherals(withServices: self.baseLayerServices), connectedPeripherals.count > 0 {
print("Already connected: \(connectedPeripherals.map{[=11=].name}), self.peripherals: \(self.peripherals)")
self.centralManager?.stopScan()
}
else {
print("scanForPeripherals")
self.centralManager?.scanForPeripherals(withServices: self.baseLayerServices, options: nil)
}
}
else {
self.showStateAlert = true // Alert is called if there is any issue with the state.
}
}
}
谢谢!!!
要记住的是,视图修饰符实际上并不只是修改视图,它们 return 是一个全新的视图。因此第一个 alert
修饰符 return 是一个以第一种方式处理警报的新视图。第二个 alert
修饰符 return 是一个新视图,它以第二种方式修改警报(覆盖第一种方法),这是唯一最终生效的方式。最外层的修饰符才是最重要的。
您可以尝试几件事,首先尝试将不同的警报修饰符附加到两个不同的视图,而不是同一个视图。
其次,您可以尝试 alert
的替代形式,它采用可选的 Identifiable 的绑定并将其传递给闭包。当值为 nil 时,什么也不会发生。当状态更改为 nil 以外的其他内容时,应出现警报。
这是一个使用 alert(item:)
形式的示例,而不是基于布尔的 alert(isPresented:)
。
enum Selection: Int, Identifiable {
case a, b, c
var id: Int { rawValue }
}
struct MultiAlertView: View {
@State private var selection: Selection? = nil
var body: some View {
HStack {
Button(action: {
self.selection = .a
}) { Text("a") }
Button(action: {
self.selection = .b
}) { Text("b") }
}.alert(item: $selection) { (s: Selection) -> Alert in
Alert(title: Text("selection: \(s.rawValue)"))
}
}
}
我有两个警报,如果布尔值为真,则调用它们。
Alert - 1 - 如果蓝牙状态有任何问题而不是供电时调用 on.This 直接从 swift 包调用命名为 BLE。代码片段如下。
Alert - 2 - 当你想取消配对外围设备给用户两个 options.Unpair 或保持在同一页面时调用。
问题: 这两个警报似乎都工作正常,但如果它们未放置在同一视图中。当我将警报放在同一视图中时,最后显示的警报从上到下顺序调用。
OS 读取第一个警报,但仅在调用时激活第二个警报。
有没有办法让这两个警报在被调用时都起作用。 我参考了以下解决方案,但我得到了相同的结果。
有 2 个代码片段
1.主要应用
import SwiftUI
import BLE
struct Dashboard: View {
@EnvironmentObject var BLE: BLE
@State private var showUnpairAlert: Bool = false
private var topLayer: HeatPeripheral {
self.BLE.peripherals.baseLayer.top
}
var body: some View {
VStack(alignment: .center, spacing: 0) {
// MARK: - Menu Bar
VStack(alignment: .center, spacing: 4) {
Button(action: {
print("Unpair tapped!")
self.showUnpairAlert = true
}) {
HStack {
Text("Unpair")
.fontWeight(.bold)
.font(.body)
}
.frame(minWidth: 85, minHeight: 35)
.cornerRadius(30)
}
}
}
.onAppear(perform: {
self.BLE.update()
})
// Alert 1 - It is called if it meets one of the cases and returns the alert
// It is presented in the function centralManagerDidUpdateState
.alert(isPresented: $BLE.showStateAlert, content: { () -> Alert in
let state = self.BLE.centralManager!.state
var message = ""
switch state {
case .unknown:
message = "Bluetooth state is unknown"
case .resetting:
message = "Bluetooth is resetting..."
case .unsupported:
message = "This device doesn't have a bluetooth radio."
case .unauthorized:
message = "Turn On Bluetooth In The Settings App to Allow Battery to Connect to App."
case .poweredOff:
message = "Turn On Bluetooth to Allow Battery to Connect to App."
break
@unknown default:
break
}
return Alert(title: Text("Bluetooth is \(self.BLE.getStateString())"), message: Text(message), dismissButton: .default(Text("OK")))
})
// Alert 2 - It is called when you tap the unpair button
.alert(isPresented: $showUnpairAlert) {
Alert(title: Text("Unpair from \(checkForDeviceInformation())"), message: Text("*Your peripheral command will stay on."), primaryButton: .destructive(Text("Unpair")) {
self.unpairAndSetDefaultDeviceInformation()
}, secondaryButton: .cancel())
}
}
func unpairAndSetDefaultDeviceInformation() {
defaults.set(defaultDeviceinformation, forKey: Keys.deviceInformation)
disconnectPeripheral()
print("Pod unpaired and view changed to Onboarding")
self.presentationMode.wrappedValue.dismiss()
DispatchQueue.main.async {
self.activateLink = true
}
}
func disconnectPeripheral(){
if skiinBLE.peripherals.baseLayer.top.cbPeripheral != nil {
self.skiinBLE.disconnectPeripheral()
}
}
}
2。 BLE 包
import SwiftUI
import Combine
import CoreBluetooth
public class BLE: NSObject, ObservableObject {
public var centralManager: CBCentralManager? = nil
public let baseLayerServices = "XXXXXXXXXXXXXXX"
let defaults = UserDefaults.standard
@Published public var showStateAlert: Bool = false
public func start() {
self.centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
self.centralManager?.delegate = self
}
public func getStateString() -> String {
guard let state = self.centralManager?.state else { return String() }
switch state {
case .unknown:
return "Unknown"
case .resetting:
return "Resetting"
case .unsupported:
return "Unsupported"
case .unauthorized:
return "Unauthorized"
case .poweredOff:
return "Powered Off"
case .poweredOn:
return "Powered On"
@unknown default:
return String()
}
}
}
extension BLE: CBCentralManagerDelegate {
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("state: \(self.getStateString())")
if central.state == .poweredOn {
self.showStateAlert = false
if let connectedPeripherals = self.centralManager?.retrieveConnectedPeripherals(withServices: self.baseLayerServices), connectedPeripherals.count > 0 {
print("Already connected: \(connectedPeripherals.map{[=11=].name}), self.peripherals: \(self.peripherals)")
self.centralManager?.stopScan()
}
else {
print("scanForPeripherals")
self.centralManager?.scanForPeripherals(withServices: self.baseLayerServices, options: nil)
}
}
else {
self.showStateAlert = true // Alert is called if there is any issue with the state.
}
}
}
谢谢!!!
要记住的是,视图修饰符实际上并不只是修改视图,它们 return 是一个全新的视图。因此第一个 alert
修饰符 return 是一个以第一种方式处理警报的新视图。第二个 alert
修饰符 return 是一个新视图,它以第二种方式修改警报(覆盖第一种方法),这是唯一最终生效的方式。最外层的修饰符才是最重要的。
您可以尝试几件事,首先尝试将不同的警报修饰符附加到两个不同的视图,而不是同一个视图。
其次,您可以尝试 alert
的替代形式,它采用可选的 Identifiable 的绑定并将其传递给闭包。当值为 nil 时,什么也不会发生。当状态更改为 nil 以外的其他内容时,应出现警报。
这是一个使用 alert(item:)
形式的示例,而不是基于布尔的 alert(isPresented:)
。
enum Selection: Int, Identifiable {
case a, b, c
var id: Int { rawValue }
}
struct MultiAlertView: View {
@State private var selection: Selection? = nil
var body: some View {
HStack {
Button(action: {
self.selection = .a
}) { Text("a") }
Button(action: {
self.selection = .b
}) { Text("b") }
}.alert(item: $selection) { (s: Selection) -> Alert in
Alert(title: Text("selection: \(s.rawValue)"))
}
}
}