iosswiftswiftuibackground-color

Remove default white background color SwiftUI


So here is the deal. I'm making a button component that will have two styles. One of the style has any backgroundColor defined by the dev and the other style has no backgroundColor but does have a border. I have implemented the style with the background color but I am trying to set up the style without background color and it always applies a default white color that I can't get rid of, making the border of the component not look right.

Button with backgroundColor:

    var mainContentView: some View {
        HStack{
            if let leadingIcon = configuration.leadingIcon {
                imageView(resource: leadingIcon, color: style.leadingIconColor, size: size.iconSize())
            }
            titleView
            if let trailingIcon = configuration.trailingIcon {
                imageView(resource: trailingIcon, color: style.trailingIconColor, size: size.iconSize())
            }
        }
        .frame(maxWidth: configuration.maxWidth ? .infinity : nil)
        .padding(.vertical, 8)
        .padding(.horizontal, 8)
        .background(Color.gray)
        .clipShape(
            .rect(
                topLeadingRadius: configuration.invertCornerRadius ? 5 : 15,
                bottomLeadingRadius: configuration.invertCornerRadius ? 15 : 5,
                bottomTrailingRadius: configuration.invertCornerRadius ? 5 : 15,
                topTrailingRadius: configuration.invertCornerRadius ? 15 : 5
            )
        )
    }

enter image description here

Button without backgroundColor:

    var mainContentView: some View {
        HStack{
            if let leadingIcon = configuration.leadingIcon {
                imageView(resource: leadingIcon, color: style.leadingIconColor, size: size.iconSize())
            }
            titleView
            if let trailingIcon = configuration.trailingIcon {
                imageView(resource: trailingIcon, color: style.trailingIconColor, size: size.iconSize())
            }
        }
        .frame(maxWidth: configuration.maxWidth ? .infinity : nil)
        .padding(.vertical, 8)
        .padding(.horizontal, 8)
        // .background(Color.clear) I've try this too
        .overlay(
            RoundedRectangle(cornerRadius: 0)
                .stroke(Color.red, lineWidth: 2)
                .clipShape(
                    .rect(
                        topLeadingRadius: configuration.invertCornerRadius ? 5 : 15,
                        bottomLeadingRadius: configuration.invertCornerRadius ? 15 : 5,
                        bottomTrailingRadius: configuration.invertCornerRadius ? 5 : 15,
                        topTrailingRadius: configuration.invertCornerRadius ? 15 : 5
                    )
                )
        )
    }

enter image description here


Solution

  • Your Button without backgroundColor didn't work in this scenario because it was based on RoundedRectangle which had cornerRadius = 0. However, if you change it to 5 or 15 you will lose 2 other edges since your view had 2 different cornerRadius values.

    You can try this approach to customize a Shape:

    struct MyRoundedRectangle: Shape {
        var topLeftRadius: CGFloat = 0
        var topRightRadius: CGFloat = 0
        var bottomRightRadius: CGFloat = 0
        var bottomLeftRadius: CGFloat = 0
    
        func path(in rect: CGRect) -> Path {
            var path = Path()
    
            let topLeft = CGPoint(x: rect.minX, y: rect.minY)
            let topRight = CGPoint(x: rect.maxX, y: rect.minY)
            let bottomRight = CGPoint(x: rect.maxX, y: rect.maxY)
            let bottomLeft = CGPoint(x: rect.minX, y: rect.maxY)
    
            path.move(to: CGPoint(x: topLeft.x + topLeftRadius, y: topLeft.y))
    
            path.addLine(to: CGPoint(x: topRight.x - topRightRadius, y: topRight.y))
            path.addArc(center: CGPoint(x: topRight.x - topRightRadius, y: topRight.y + topRightRadius),
                        radius: topRightRadius,
                        startAngle: Angle(degrees: -90),
                        endAngle: Angle(degrees: 0),
                        clockwise: false)
    
            path.addLine(to: CGPoint(x: bottomRight.x, y: bottomRight.y - bottomRightRadius))
            path.addArc(center: CGPoint(x: bottomRight.x - bottomRightRadius, y: bottomRight.y - bottomRightRadius),
                        radius: bottomRightRadius,
                        startAngle: Angle(degrees: 0),
                        endAngle: Angle(degrees: 90),
                        clockwise: false)
    
            path.addLine(to: CGPoint(x: bottomLeft.x + bottomLeftRadius, y: bottomLeft.y))
            path.addArc(center: CGPoint(x: bottomLeft.x + bottomLeftRadius, y: bottomLeft.y - bottomLeftRadius),
                        radius: bottomLeftRadius,
                        startAngle: Angle(degrees: 90),
                        endAngle: Angle(degrees: 180),
                        clockwise: false)
    
            path.addLine(to: CGPoint(x: topLeft.x, y: topLeft.y + topLeftRadius))
            path.addArc(center: CGPoint(x: topLeft.x + topLeftRadius, y: topLeft.y + topLeftRadius),
                        radius: topLeftRadius,
                        startAngle: Angle(degrees: 180),
                        endAngle: Angle(degrees: 270),
                        clockwise: false)
    
            return path
        }
    }
    

    And then using .stroke as you wish:

        var body: some View {
            Button {
            } label: {
                Text("Button")
                    .foregroundStyle(.blue)
            }
            .frame(minWidth: 100, minHeight: 30)
            .overlay {
                MyRoundedRectangle(
                    topLeftRadius: 15,
                    topRightRadius: 5,
                    bottomRightRadius: 15,
                    bottomLeftRadius: 5
                )
                .stroke(.red, lineWidth: 1)
            }
        }
    

    Output:

    enter image description here