【问题标题】:Using ternary operator in SwiftUI causes mismatching types error, why?在 SwiftUI 中使用三元运算符会导致类型不匹配错误,为什么?
【发布时间】:2021-06-30 08:33:57
【问题描述】:

我目前一直在使用这个 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)
)

【问题讨论】:

  • 是多余的)吗?
  • @Don 不,那是一个错字,不错:D

标签: swift swiftui


【解决方案1】:

除了@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

【讨论】:

    【解决方案2】:

    您收到错误是因为 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
        }
    }
    

    【讨论】:

    • 这是解释性的,但我不得不问,我应该在哪里放置与深色和白色相关的通用修改?
    • 您肯定需要在某个地方使用switchif——这只是您希望它抽象到何种程度的问题。我添加了一个使用视图修饰符的示例。您仍然可以使用lightAndDarkModifications 获得受全局影响的代码,然后有条件地应用修饰符——您仍然会有 一些 重复,就像您最初的问题一样。在这种情况下,它出现在按钮样式的makeBody 中——至少它不会在你的实际视图代码中到处重复。
    • 使用没有视图修饰符的方法在 switch 语句中只返回.light。嗯嗯
    • 我相信这个答案大部分是正确的,但我的 SwiftUI 经验有限,我无法让它正常工作。我能够使用不透明类型使其与下面的答案一起使用。
    猜你喜欢
    • 2014-11-06
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-09
    • 1970-01-01
    相关资源
    最近更新 更多