如何使用 ForEach 循环让 Picker 到 return VideoFormat var?
How can I get Picker to return a VideoFormat var using a ForEach loop?
我正在尝试使用选择器通过 ForEach 循环从 Twilio 的视频 API select VideoFormat。循环正在运行——它列出了所有格式正确的格式字符串。
这是我的看法,SettingsView
:
import SwiftUI
struct SettingsView: View {
@EnvironmentObject var twilioState: TwilioState
var body: some View {
Form {
Section(header: Text("Stream")) {
HStack {
Text("Device")
Spacer()
Text("\(twilioState.captureDevice?.localizedName ?? "N/A")")
}
这就是我 运行 遇到麻烦的地方。我似乎无法让 Picker
为我的 selection
、$twilioState.videoFormat
赋值。我怀疑是不是跟id
和VideoFormat
不符合Hashable
有关?我正在考虑将 selection
更改为 Int
并使用 ForEach
的范围,例如 0..<twilioState.videoFormats.count
.
Picker("Select a Format", selection: $twilioState.videoFormat) {
if let videoFormats = twilioState.videoFormats {
ForEach(videoFormats, id: \.self) {
Text("\(twilioState.getVideoFormatString(videoFormat: [=12=]))")
.tag([=12=])
}
}
}
.disabled(twilioState.videoFormats == nil)
剩下的是 twilioState.videoFormat
的列表,因为我试图找出如何成功实施 Picker
。
HStack {
Text("Format")
Spacer()
if let videoFormat = twilioState.videoFormat {
Text("\(twilioState.getVideoFormatString(videoFormat: videoFormat))")
} else {
Text("N/A")
}
}
}
}
.navigationBarTitle("Settings")
}
}
这是我的状态模型,TwilioState
:
import Foundation
import TwilioVideo
import Combine
class TwilioState: ObservableObject {
let twilioService = TwilioService()
private var cancellables = Set<AnyCancellable>()
var camera: CameraSource?
@Published var videoFormat: VideoFormat?
@Published var videoFormats: [VideoFormat]?
@Published var captureDevice: AVCaptureDevice?
@Published var twilioError: TwilioError?
init() {
twilioService.setCaptureDevice(captureDevice: self.captureDevice)
.sink { completion in
switch completion {
case let .failure(twilioError):
return self.twilioError = twilioError
case .finished:
return print("Capture device set")
}
} receiveValue: { captureDevice in
self.captureDevice = captureDevice
}
.store(in: &cancellables)
twilioService.getVideoFormats(captureDevice: self.captureDevice!)
.sink { completion in
switch completion {
case let .failure(twilioError):
return self.twilioError = twilioError
case .finished: return print("Capture device formats set")
}
} receiveValue: { videoFormats in
self.videoFormats = videoFormats
}
.store(in: &cancellables)
}
func getVideoFormatString(videoFormat: VideoFormat) -> String {
return "\(videoFormat.dimensions.width) x \(videoFormat.dimensions.height) @ \(videoFormat.frameRate)"
}
deinit {
// We are done with camera
if let camera = self.camera {
camera.stopCapture()
self.camera = nil
}
}
}
如果有帮助,这是服务函数 getVideoFormats()
,它正在为我的模型 @Published videoFormats
提供值,TwilioState
:
func getVideoFormats(captureDevice: AVCaptureDevice) -> AnyPublisher<[VideoFormat], TwilioError> {
return Just(captureDevice)
.map { captureDevice -> [VideoFormat] in
return CameraSource.supportedFormats(captureDevice: captureDevice)
.compactMap { [=15=] as? VideoFormat }
}
.setFailureType(to: TwilioError.self)
.eraseToAnyPublisher()
}
我通过使用标记修饰符将选择类型转换为可选来解决这个问题:
Picker("Select a Format", selection: $twilioState.videoFormat) {
if let videoFormats = twilioState.videoFormats {
ForEach(videoFormats, id: \.self) { videoFormat in
Text("\(twilioState.getVideoFormatString(videoFormat: videoFormat))")
.tag(videoFormat as VideoFormat?)
}
}
}
查看此 post 了解更多信息:Picker for optional data type in SwiftUI?
我正在尝试使用选择器通过 ForEach 循环从 Twilio 的视频 API select VideoFormat。循环正在运行——它列出了所有格式正确的格式字符串。
这是我的看法,SettingsView
:
import SwiftUI
struct SettingsView: View {
@EnvironmentObject var twilioState: TwilioState
var body: some View {
Form {
Section(header: Text("Stream")) {
HStack {
Text("Device")
Spacer()
Text("\(twilioState.captureDevice?.localizedName ?? "N/A")")
}
这就是我 运行 遇到麻烦的地方。我似乎无法让 Picker
为我的 selection
、$twilioState.videoFormat
赋值。我怀疑是不是跟id
和VideoFormat
不符合Hashable
有关?我正在考虑将 selection
更改为 Int
并使用 ForEach
的范围,例如 0..<twilioState.videoFormats.count
.
Picker("Select a Format", selection: $twilioState.videoFormat) {
if let videoFormats = twilioState.videoFormats {
ForEach(videoFormats, id: \.self) {
Text("\(twilioState.getVideoFormatString(videoFormat: [=12=]))")
.tag([=12=])
}
}
}
.disabled(twilioState.videoFormats == nil)
剩下的是 twilioState.videoFormat
的列表,因为我试图找出如何成功实施 Picker
。
HStack {
Text("Format")
Spacer()
if let videoFormat = twilioState.videoFormat {
Text("\(twilioState.getVideoFormatString(videoFormat: videoFormat))")
} else {
Text("N/A")
}
}
}
}
.navigationBarTitle("Settings")
}
}
这是我的状态模型,TwilioState
:
import Foundation
import TwilioVideo
import Combine
class TwilioState: ObservableObject {
let twilioService = TwilioService()
private var cancellables = Set<AnyCancellable>()
var camera: CameraSource?
@Published var videoFormat: VideoFormat?
@Published var videoFormats: [VideoFormat]?
@Published var captureDevice: AVCaptureDevice?
@Published var twilioError: TwilioError?
init() {
twilioService.setCaptureDevice(captureDevice: self.captureDevice)
.sink { completion in
switch completion {
case let .failure(twilioError):
return self.twilioError = twilioError
case .finished:
return print("Capture device set")
}
} receiveValue: { captureDevice in
self.captureDevice = captureDevice
}
.store(in: &cancellables)
twilioService.getVideoFormats(captureDevice: self.captureDevice!)
.sink { completion in
switch completion {
case let .failure(twilioError):
return self.twilioError = twilioError
case .finished: return print("Capture device formats set")
}
} receiveValue: { videoFormats in
self.videoFormats = videoFormats
}
.store(in: &cancellables)
}
func getVideoFormatString(videoFormat: VideoFormat) -> String {
return "\(videoFormat.dimensions.width) x \(videoFormat.dimensions.height) @ \(videoFormat.frameRate)"
}
deinit {
// We are done with camera
if let camera = self.camera {
camera.stopCapture()
self.camera = nil
}
}
}
如果有帮助,这是服务函数 getVideoFormats()
,它正在为我的模型 @Published videoFormats
提供值,TwilioState
:
func getVideoFormats(captureDevice: AVCaptureDevice) -> AnyPublisher<[VideoFormat], TwilioError> {
return Just(captureDevice)
.map { captureDevice -> [VideoFormat] in
return CameraSource.supportedFormats(captureDevice: captureDevice)
.compactMap { [=15=] as? VideoFormat }
}
.setFailureType(to: TwilioError.self)
.eraseToAnyPublisher()
}
我通过使用标记修饰符将选择类型转换为可选来解决这个问题:
Picker("Select a Format", selection: $twilioState.videoFormat) {
if let videoFormats = twilioState.videoFormats {
ForEach(videoFormats, id: \.self) { videoFormat in
Text("\(twilioState.getVideoFormatString(videoFormat: videoFormat))")
.tag(videoFormat as VideoFormat?)
}
}
}
查看此 post 了解更多信息:Picker for optional data type in SwiftUI?