在 SwiftUI 中使用三元运算符会导致类型不匹配错误,为什么?

时间:2021-04-03 23:35:47

标签: swift swiftui

我目前一直在使用此 Environment 变量来调整应用程序中 DarkLight 模式的内容。

<块引用>

@Environment(.colorScheme) var colorScheme

我遇到的问题是使用 var 有条件地设置按钮样式。这种方法效果很好。

if colorScheme == .dark {
                    Button("Create Account", action: {
                        
                    }).buttonStyle(CinderDarkButtonStyle(geometry: geometry))
                } else {
                    Button("Create Account", action: {
                        
                    }).buttonStyle(CinderLightButtonStyle(geometry: geometry))
                }

但是这样做会导致我在相对简单的用户界面上到处重复代码。每当我尝试以这种方式执行此操作时,我都会遇到错误,指出我的类型不匹配。

Button("Create Account", action: {
                            //DO SOME ACTION
                        }).buttonStyle(
colorScheme == .dark ? 
     CinderDarkButtonStyle(geometry: geometry) :
     CinderLightButtonStyle(geometry: geometry)
)

2 个答案:

答案 0 :(得分:0)

您会收到错误消息,因为 CinderDarkButtonStyleCinderLightButtonStyle 实际上是不同的类型。而且,ButtonStyle 具有关联类型,因此您不能直接转换为 ButtonStyle

如果这是一个普通的 View 而不是 ButtonStyle,您可以使用 AnyView 进行一些类型擦除,以便类型相同。

在这种情况下,似乎只是移动关于在自定义按钮样式中显示哪种按钮样式的逻辑会更清晰:

struct MyTestView : View {
    var body: some View {
        GeometryReader { geometry in
            Button("Create Account", action: {
                //DO SOME ACTION
            })
            .buttonStyle(CinderButtonStyle(geometry: geometry))
        }
    }
}

struct CinderButtonStyle : ButtonStyle {
    var geometry : GeometryProxy
    @Environment(\.colorScheme) private var colorScheme
    
    @ViewBuilder func makeBody(configuration: Configuration) -> some View {
        switch colorScheme {
        case .dark:
            darkBody(configuration: configuration)
        case .light:
            lightBody(configuration: configuration)
        @unknown default:
            lightBody(configuration: configuration)
        }
    }
    
    @ViewBuilder func lightBody(configuration: Configuration) -> some View {
        configuration.label //light modifications
    }
    
    @ViewBuilder func darkBody(configuration: Configuration) -> some View {
        configuration.label //dark modifications
    }
}

更新,使用视图修饰符:


struct CinderButtonStyle : ButtonStyle {
    var geometry : GeometryProxy
    @Environment(\.colorScheme) private var colorScheme
    
    @ViewBuilder func makeBody(configuration: Configuration) -> some View {
        switch colorScheme {
        case .dark:
            lightAndDarkModifications(configuration: configuration)
                .modifier(DarkModifier())
        default:
            lightAndDarkModifications(configuration: configuration)
                .modifier(LightModifier())
        }
    }
    
    @ViewBuilder func lightAndDarkModifications(configuration: Configuration) -> some View {
        configuration.label
    }
}

struct DarkModifier : ViewModifier {
    func body(content: Content) -> some View {
        content
    }
}

struct LightModifier : ViewModifier {
    func body(content: Content) -> some View {
        content
    }
}

答案 1 :(得分:0)

除了 @Don 所说的额外的 ) 之外,CinderDarkButtonStyleCinderLightButtonStyle 是不同的结构体。它们不是同一类型。

您可以做的是创建一个返回不透明类型的自定义函数,如this answer 中所述。尝试这样的事情:

struct ContentView: View {
    @State var colorScheme = ColorScheme.dark

    var body: some View {
        GeometryReader { geometry in
            Button("Create Account", action: {
                //DO SOME ACTION
            })
            .buttonStyle(for: colorScheme, geometry: geometry) /// use custom buttonStyle function
        }
    }
}

extension Button {
    @ViewBuilder
    func buttonStyle(for colorScheme: ColorScheme, geometry: GeometryProxy) -> some View {
        switch colorScheme {
        case .light:
            buttonStyle(CinderDarkButtonStyle(geometry: geometry))
        case .dark:
            buttonStyle(CinderLightButtonStyle(geometry: geometry))
        }
    }
}

以上基于 buttonStyle(CinderDarkButtonStyle(geometry: geometry))buttonStyle(CinderLightButtonStyle(geometry: geometry))colorScheme 修饰符之间切换。