在 SwiftUI 中播放音频时无法更新行颜色

问题描述

在使用 iOS 开发 SwiftUI 应用程序时,我面临以下情况。我已经设置了一个自定义环境键。这是 SceneDelegate.swift 文件中的相关代码

private struct RowColorMaster: EnvironmentKey {
    static var defaultValue: Binding<[[String:Color]]> = .constant([[:]])
}

extension EnvironmentValues {
    var rowColorMasterDico: Binding<[[String:Color]]> {
        get {self[RowColorMaster.self]}
        set {self[RowColorMaster.self] = newValue}
    }
}


class SceneDelegate: UIResponder,UIWindowSceneDelegate {
    var window: UIWindow?
    var rowColorMasterDico:[[String:Color]] = []

    func scene(_ scene: UIScene,willConnectTo session: UIScenesession,options connectionoptions: UIScene.Connectionoptions) {
        .....
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        .....
        rowColorMasterDico = .....

        print("rowColorMasterDico -> \(rowColorMasterDico.count)")

        let contentView = ContentView(sectionsList: sectionsList,itemmasterList: sentceMasterarray)
                                .environment(\.managedobjectContext,context)
                                .environment(\.rowColorMasterDico,Binding(get: {self.rowColorMasterDico},set: {
                                                        newValue in
                                                        self.rowColorMasterDico = newValue
                                                     }))
        .....
    }
    .....
}

再往下,在视图层次结构中,在一些视图文件中:

struct SectionView: View {
    var moc:NSManagedobjectContext
    .....
    @Environment(\.rowColorMasterDico) var rowColorMasterDico
    .....

    func handleEvent(_ file: String,flag: Bool) {
        // This function is called when an audio file
        // starts or ends playing.
        if rowColorMasterDico.wrappedValue.count != 10 {
            // This should not happen! But for some reason it sometimes does.
            print("rowColorMasterDico is messed up !")
            return
        }

        // Check that rowColorMasterDico.wrappedValue[page.index][file] changes value.
        print("CLR(Before)=\(rowColorMasterDico.wrappedValue[page.index][file]!)")
        rowColorMasterDico.wrappedValue[page.index][file] = flag ? Color.red : Color.white
        print("CLR(After)=\(rowColorMasterDico.wrappedValue[page.index][file]!)")
    }
    .....


    var body: some View {
        vstack {
            ListItemView(itemList: itmMstrList[page.index],moc: moc,rowColorDico: rowColorMasterDico.wrappedValue[page.index])
            Button(action: {
                if !soundManager.isPlaying {self.playAllAudio(itmMstrList[page.index])}
                else {soundManager.stopAudio()}
            })
            {
                Image(uiImage: UIImage(named: "speaker.png")!)
                    .padding(.bottom,17)
            }
        }
    }
    .....


struct ListItemView: View {
    let crnrRad:CGFloat = 13.0,bgGreyLvl = 0.37,fgGreyLvl = 0.93
    var itemList:[ItemList],moc:NSManagedobjectContext
    @State var rowColorDico:[String:Color]

    .....
    
    func diddismiss() {
        // Handle the dismissing action.
        print(#function)
    }
    
    var body: some View {
        List {
            ForEach(self.itemList) {
                item in
                HStack {
                    Spacer()
                    Button(action: {
                        self.handleRowItem(item)
                    })
                    {
                        RowItemView(expression: item.expression!,fgTxtColor: rowColorDico[item.soundFile!] ?? Color.orange)
                    }
                    Spacer()
                }
            }
        }.sheet(item: $itemPage,ondismiss: diddismiss) {
            sntnc in
            .....
        }
        
    }
}


struct RowItemView: View {
    var expression:String
    @State var fgTxtColor:Color
    let crnrRad:CGFloat = 13.0,bgGreyLvl = 0.37
    
    var body: some View {
        Text(expression)
            .foregroundColor(fgTxtColor)
            .font(.headline)
            .padding(.horizontal,11).padding(.vertical,15)
            .background(Color(.sRGB,red: bgGreyLvl,green: bgGreyLvl,blue:bgGreyLvl,opacity: 1.0))
            .cornerRadius(crnrRad)
            .overlay(RoundedRectangle(cornerRadius: crnrRad)
                    .stroke(Color.yellow,linewidth: 3))
    }
}

问题来了。当我在 ListItemView 中播放音频文件列表时,匹配的行项目应该更改播放文件的颜色。该工作在 handleEvent 函数内完成,我可以检查这是否按预期发生。但是列表中显示的颜色不会改变。这是为什么?

我设置环境变量 rowColorMasterDico 的方式有误吗? 还是我错过了其他东西?我已经尝试了上面代码的许多不同变体,但我无法让它工作。我希望有人能看到并指出某个地方的错误

解决方法

以防万一这对其他人有用,我想报告我通过参考 this 解决了我的问题,同时再次查看了我自己的代码。