一个视图中的多个警报只能在swiftui中始终运行最后一个警报

问题描述 投票:0回答:1

我有两个警报,如果布尔值为true,则会调用该警报。

Alert-1-如果蓝牙状态除了开机以外还有其他问题,则调用它。直接从名为BLE的快速软件包中调用它。代码段如下。

Alert-2-当您要取消与外围设备的配对时为用户提供两个选项。取消配对或保留在同一页面上。

问题:两种警报似乎都可以正常工作,但是如果未将它们放置在同一视图中。当我将警报放置在同一视图中时,从上到下的顺序将调用最后显示的警报。

操作系统读取第一个警报,但仅在调用第二个警报时激活。

是否有一种方法可以使两个警报都被调用。我提到了以下解决方案,但得到了相同的结果。

[Solution 1Solution 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{$0.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.
        }
    }
}

谢谢!!

swiftui uialertview core-bluetooth swift5.1
1个回答
0
投票

要记住的是,视图修饰符实际上并不只是修改视图,它们还返回一个全新的视图。因此,第一个alert修饰符将返回一个以第一种方式处理警报的新视图。第二个alert修饰符返回一个新视图,该视图以第二种方式修改警报(覆盖第一种方法),并且这是唯一最终生效的视图。最外层的修饰符很重要。

您可以尝试几种方法,首先尝试将不同的警报修饰符附加到两个不同的视图,而不是同一视图。

第二,您可以尝试alert的另一种形式,该形式采用可选Identifiable的Binding并将其传递给闭包。当值为零时,什么也不会发生。当状态更改为nil以外的其他值时,将出现警报。现在,我在将其与Alerts配合使用时遇到了问题,但是如果可以选择的话,它可以在Sheets上正常工作。

类似这样的东西:

enum Selection: Int, Identifiable {
  case a, b, c
  var id: Int { rawValue }
}

var view: View {

@State var selection: Selection? = nil

[View]
.alert(item: $selection) { (s: Selection) -> Alert in
   Alert(...) // use s to identify
}
© www.soinside.com 2019 - 2024. All rights reserved.