skip to Main Content

In my project, I am using my custom shape as a button’s label. Now, I am trying to create a custom ButtonStyle which changes the custom shape’s color whenever a button is currently pressed.

If I were to use a "normal" Button label, e.g. a Text, I could do this:

struct LightGrayButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .foregroundColor(configuration.isPressed ? .black : .red)
    }
}

However, configuration.label does not have any Shape specific view modifiers, making it impossible to alter the color using .fill for example.

This is the rest of my code:

Button {
   action()
} label: {
   RingSegment() // this is my custom shape
}
.buttonStyle(LightGrayButtonStyle()) // I apply my custom button style

How can I now change the color of my custom shape inside my custom ButtonStyle? Alternatively, how can I make my custom shape respect the provided foregroundColor which I can set inside the makeBody method implemented by my LightGrayButtonStyle?

2

Answers


  1. Chosen as BEST ANSWER

    The solution I went for is to apply the foregroundColor modifier inside the makeBody function and use that color when filling my custom shape.

    This is my code:

    // Declare Button Style
    struct LightGrayRingSegmentButtonStyle: ButtonStyle {
        func makeBody(configuration: Self.Configuration) -> some View {
            configuration.label
                .foregroundColor(configuration.isPressed ? .red : .blue)
        }
    }
    
    
    Button {
        action()
    } label: {
        RingSegment()
            // respect foregroundColor which we set inside the custom button style
            .fill(.foreground)
    }
    .buttonStyle(LightGrayRingSegmentButtonStyle())
    

  2. You can move all the code inside the ButtonStyle

    struct MyShapeButtonStyle<S: Shape>: ButtonStyle {
        ///Custom Shape
        let shape: S
        ///Default Color
        let color: Color
        ///Uses any Shape
        init(shape: S, color: Color) {
            self.shape = shape
            self.color = color
        }
        ///Default is a `Circle`
        init(color: Color) where S == Circle {
            self.shape = Circle()
            self.color = color
        }
        
        func makeBody(configuration: Self.Configuration) -> some View {
            //Custom shape
            shape
                //Fill for the shape
                .fill(configuration.isPressed ? .black : color)//Keep the ability to put a label in the button
                .overlay(content: {
                    //Keep the ability to have a custom label.
                    configuration.label
                        .foregroundColor(.white)
                })
                .foregroundColor(configuration.isPressed ? .black : color)
        }
    }
    

    Then you can pass in any Shape and any Color.

    struct CustomButtonShapeView: View {
        var body: some View {
            VStack{
                Button("Test") {
                    print("test")
                }
                .buttonStyle(MyShapeButtonStyle(color: .red))
                
                Button("Test") {
                    print("test")
                }
                .buttonStyle(MyShapeButtonStyle(shape: Rectangle(), color: .blue))
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search