[英]Picker Options Not Updating Dynamically SwiftUI
I have a picker that needs to dynamically update as it finds new BLE peripherals.我有一个选择器,它需要在找到新的 BLE 外围设备时动态更新。 However, the picker never updates with the new values.
但是,选择器永远不会使用新值进行更新。
I had a List that was working fine with the following code, so I know everything is ok in my BLE Manager:我有一个使用以下代码可以正常工作的列表,所以我知道在我的 BLE 管理器中一切正常:
List(bleManager.peripheralsDisp) { peripheral in
Text(peripheral.displayName)
}.frame(height: 300)
However, the same code used for the picker, does not work:但是,用于选择器的相同代码不起作用:
Picker(selection: $selectedDevice, label: Text("")) {
ForEach(self.bleManager.peripheralsDisp, id: \.self) { peripheral in
Text(peripheral.displayName)
}
}
.frame(width: 200, height: 40, alignment: .center)
Any advice as to how to get the picker options to dynamically update would be much appreciated任何关于如何让选择器选项动态更新的建议将不胜感激
EDIT:编辑:
Here is my BLEManager.swift file这是我的 BLEManager.swift 文件
import Foundation
import CoreBluetooth
struct PeripheralDisp: Hashable {
let serialNo: Int
let displayName: String
}
class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate {
@Published var isSwitchedOn = false
@Published var peripheralsDisp = [PeripheralDisp]()
var myCentral: CBCentralManager!
var myPeripheral: CBPeripheral!
override init() {
super.init()
myCentral = CBCentralManager(delegate: self, queue: nil)
myCentral.delegate = self
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
isSwitchedOn = true
startScanning()
}
else {
isSwitchedOn = false
stopScanning()
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
var peripheralName: String = ""
var peripheralSerialNo: Int = 0
var peripheralDisplayName: String = ""
if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
peripheralName = name
}
else {
peripheralName = "Unknown"
}
let newPeripheralDisp = PeripheralDisp(serialNo: newPeripheralDisp.count, displayName: peripheralDisplayName)
peripheralsDisp.append(newPeripheralDisp) //peripheralDisplayName)
}
func startScanning() {
print("StartScanning")
myCentral.scanForPeripherals(withServices: nil, options: nil)
}
func stopScanning() {
print("StopScanning")
myCentral.stopScan()
}
}
Full ContentView.swift:完整内容查看.swift:
struct ContentView: View {
@EnvironmentObject var viewRouter: ViewRouter
@ObservedObject var bleManager = BLEManager()
@State var selectedDevice = 0
var body: some View {
VStack(spacing: 10) {
Spacer()
// Device Picker
Picker(selection: $selectedDevice, label: Text("")) {
ForEach(self.bleManager.peripheralsDisp, id: \.self) { peripheral in
Text(peripheral.displayName)
}
}
.frame(width: 200, height: 40, alignment: .center)
/*List(bleManager.peripherals) { peripheral in
Text(peripheral.displayName)
}.frame(height: 300)
Spacer()*/
}
}
}
There are a couple of issues here.这里有几个问题。 First SwiftUI's
ForEach
behaves differently for static content and dynamic content.首先 SwiftUI 的
ForEach
对于 static 内容和动态内容的行为不同。 If you want your content to be dynamic, make your model conform to Identifiable
and use the overload of ForEach
that just takes a sequence of Identifiable
.如果您希望您的内容是动态的,请使您的 model 符合
Identifiable
并使用仅采用Identifiable
序列的ForEach
的重载。 Second you are changing the list so its possible that the selection could change as items drop in an out.其次,您正在更改列表,因此选择可能会随着项目的退出而改变。 I suppose you could just reset the selection to 0 if the selected item is deleted.
我想如果所选项目被删除,您可以将选择重置为 0。 to do this you should move the selection into your
ObservableObject
and not your view.为此,您应该将选择移动到您的
ObservableObject
而不是您的视图中。 I actually think the conceptually simpler idea here is to use a list and not a picker.我实际上认为这里概念上更简单的想法是使用列表而不是选择器。 Just update the list and when they tap on an item you select it.
只需更新列表,当他们点击您 select 的项目时。 (ie the list does not need to maintain the idea that some item is always selected while the picker does).
(即列表不需要保持选择器总是选择某些项目的想法)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.