Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Background Colors for layers in custom control

Tags:

swiftui

I'm trying to create a custom toggle button control in SwiftUI where the user can see two textual values in a rounded capsule with the selected value showing in one color and the unselected value showing in a different color. The example code I am doing this for would be on a login/join screen where the user can toggle between seeing a login screen or a join screen. My issue is I can't figure out to get my background colors to work as shown below. In my example below the green color around login is showing the selected value and the gray value for join is showing the unselected option. My issue is I want the space in between the two values that looks like a white hourglass to be filled in with the same unselected color (gray).

enter image description here

My code is as follows:

struct LoginJoinToggle : View {
@State var showLogin: Bool = true

var body: some View {
    var leftColor: Color = Color.green
    var rightColor: Color = Color.gray
    var leftForegroundColor: Color = Color.white
    var rightForegroundColor: Color = Color.black

    if (showLogin == false){
        leftColor = Color.gray
        rightColor = Color.green
        leftForegroundColor = Color.black
        rightForegroundColor = Color.white
    }
    return HStack{
        Text("Login")
            .font(.headline)
            .foregroundColor(leftForegroundColor)
            .padding()
            .frame(minWidth: 0, maxWidth: .infinity)
            .background(leftColor)
            .cornerRadius(40.0)
            .onTapGesture {self.showLogin = true}
        Text("Join")
            .font(.headline)
            .foregroundColor(rightForegroundColor)
            .padding()
            .frame(minWidth: 0, maxWidth: .infinity)
            .background(rightColor)
            .cornerRadius(40.0)
            .onTapGesture {self.showLogin = false}
    }.overlay(
        RoundedRectangle(cornerRadius: 40)
            .stroke(Color.green, lineWidth: 1)
    )
}

I can get the hourglass area to fill in correctly by adding a background color of gray to the HStack as shown below but then it also shows the grey color for the entire hstack area, bleeding outside the rounded corners.

    }.overlay(
        RoundedRectangle(cornerRadius: 40)
            .stroke(Color.green, lineWidth: 1)
    ).background(Color.gray)

enter image description here

I've also tried setting the background to gray for the RoundedRectangle object but then it overlays that color over everything as shown below:

enter image description here

I'm assuming/hoping there is a way for to influence that middle area (hourglass) background color with the overlay but I can't seem to figure out how to make it work. Any suggestions would be greatly appreciated.

like image 972
Chris Dellinger Avatar asked Oct 03 '19 02:10

Chris Dellinger


2 Answers

You can use shapes as well with your background modifier instead using a Color.

Change

 }.overlay(
    RoundedRectangle(cornerRadius: 40)
        .stroke(Color.green, lineWidth: 1)
).background(Color.gray)

to

 }.overlay(
    RoundedRectangle(cornerRadius: 40)
        .stroke(Color.green, lineWidth: 1)
).background(RoundedRectangle(cornerRadius: 40).fill(Color.pink)) 

and it will work.

Of course the pink color is only to make the area more visible.

like image 189
Marc T. Avatar answered Nov 13 '22 22:11

Marc T.


What you need is one more modifier to cut off anything outside the thin green outline, add this after .background:

.clipShape(RoundedRectangle(cornerRadius: 40))

EDIT

Capsule is a better shape to use in place of RoundedRectangle to achieve matching curves:

var body: some View {
    HStack {
        Text("Login")
            .font(.headline)
            .foregroundColor(showLogin ? Color.white : .black)
            .padding()
            .frame(minWidth: 0, maxWidth: .infinity)
            .background(Capsule().fill(showLogin ? Color.green : .gray))
            .onTapGesture { self.showLogin = true }
        Text("Join")
            .font(.headline)
            .foregroundColor(!showLogin ? Color.white : .black)
            .padding()
            .frame(minWidth: 0, maxWidth: .infinity)
            .background(Capsule().fill(!showLogin ? Color.green : .gray))
            .onTapGesture { self.showLogin = false }
    }   .background(Capsule().fill(Color.gray))
        .overlay(Capsule().stroke(Color.green, lineWidth: 1))

}
like image 36
LuLuGaGa Avatar answered Nov 13 '22 20:11

LuLuGaGa