Home > Software engineering >  `.background` goes wrong in `.background()` modifier in SwiftUI
`.background` goes wrong in `.background()` modifier in SwiftUI

Time:05-11

I'm trying to create a ButtonStyle. I want to let the background color be buttonBackgroundHover color which is already created in Assets.xcassets, and other time remains the default background color (same as the background color of the window). So I tried the code below, but Xcode said an error: Member 'background(ignoresSafeAreaEdges:)' expects argument of type 'Color'

struct PlayerButton: ButtonStyle {

    @State private var isOnHover: Bool = false

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .background(isOnHover ? Color("buttonBackgroundHover") : .background)
    }
}

But if I replace .background(isOnHover ? Color("buttonBackgroundHover") : .background) with .background(.background), there's no argue. I wonder what's wrong with that and how can I solve this problem. I would appreciate your help.

CodePudding user response:

The background method is declared like this:

func background<S>(_ style: S, ignoresSafeAreaEdges edges: Edge.Set = .all) -> some View where S : ShapeStyle

Notice that the argument it takes is of type S where S : ShapeStyle. When you do .background(.red) or .background(.background), S is Color or BackgroundStyle respectively.

However, when you pass in:

isOnHover ? Color("buttonBackgroundHover") : .background

There is no single type S that works. You want S to be either Color or BackgroundStyle, but the type of the above expression can only be one type of those types. The compiler sees that since Color("buttonBackgroundHover") is of type Color, it mistakenly thinks that you want the third operand .background to be of type Color too. But there is no such property as Color.background, but since Color is a view, it has a background method too, and that is what .background gets resolved to. It expects a Color argument, because you are calling an instance method without an instance (Color.background).

Anyway, there is a type eraser for ShapeStyle - AnyShapeStyle. Apply that to make both branches of the conditional expression the same type:

.background(isOnHover ? AnyShapeStyle(Color("buttonBackgroundHover")) : AnyShapeStyle(.background))

CodePudding user response:

There is no color Color.background - it tries to apply same .background() modifier, but there is Color first in ternary operator, so types conflict - error.

I assume it was expected

.background(isOnHover ? Color("buttonBackgroundHover") : 
                        Color(uiColor: UIColor.systemBackground))  // << this !!
  • Related