如何让 Picker 使用 ForEach 循环返回 VideoFormat var?

Posted

技术标签:

【中文标题】如何让 Picker 使用 ForEach 循环返回 VideoFormat var?【英文标题】:How can I get Picker to return a VideoFormat var using a ForEach loop? 【发布时间】:2021-02-21 15:48:26 【问题描述】:

我正在尝试使用 Picker 通过 ForEach 循环从 Twilio 的视频 API 中选择一个 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 赋值。我怀疑这与idVideoFormat 不符合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: $0))")
                                .tag($0)
                        
                    
                
                .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(),它在我的模型TwilioState 中向@Published videoFormats 提供值:

    func getVideoFormats(captureDevice: AVCaptureDevice) -> AnyPublisher<[VideoFormat], TwilioError> 
        return Just(captureDevice)
            .map  captureDevice -> [VideoFormat] in
                return CameraSource.supportedFormats(captureDevice: captureDevice)
                    .compactMap  $0 as? VideoFormat 
            
            .setFailureType(to: TwilioError.self)
            .eraseToAnyPublisher()
    

【问题讨论】:

【参考方案1】:

我通过使用标签修饰符将选择类型转换为可选类型解决了这个问题:

                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?)
                        
                    
                

查看此帖子了解更多信息:Picker for optional data type in SwiftUI?

【讨论】:

以上是关于如何让 Picker 使用 ForEach 循环返回 VideoFormat var?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:如何根据 Picker 的值更新 ForEach 循环的范围

SwiftUI Picker 填充问题 - 选择器中的 ForEach 循环不填充

如何在 Swiftui 中与其他组件一起在 ScrollView 或 VStack 中完全显示 Picker?

SwiftUI:使用 Picker(分段)更改 ForEach 源或获取请求

forEach的使用方法

无法让 ForEach 循环在 SwiftUI 中使用嵌套的 JSON 数据运行 [关闭]