◀ Home

How To Read Foreground and Tint Colors in SwiftUI Views

Problem

Apple’s built-in SwiftUI views rely on the foregroundColor(Color?) and tint(Color?) view modifiers to customize the colors they are drawn with. Unlike many other built-in view modifiers, neither the foreground color nor the tint color are readable through the EnvironmentValues struct or the @Environment property wrapper.

We want to allow our views to be customized using the same view modifiers instead of passing colors through the view initializer or defining custom environment keys.

Solution

Both values can be read from the environment by view modifiers that accept a ShapeStyle for filling, like View.background(in:, fillStyle:) and Shape.fill(_:, style:).

This may seem restrictive – since it’s limited to filling shapes, and not exposed through Color or an environment key – but it’s really not. Any custom drawing we want to do is inevitably done through Shape (e.g. drawing Paths) and this tool serves that use case. Any other view composition that is not custom drawing is just sticking together other pre-made views that should already respond to foregroundColor(Color?) and/or tint(Color?). Thus, there is no use case where we would want to use either value and cannot.

Apple gave us the minimum viable solution to solve this problem because they understand what our gap is. They did not expose foregroundColor or tint through a static property on Color or instance property on EnvironmentValue because those would not solve any additional problems that cannot be solved with ShapeStyle and built-in views.

Foreground Color

The value set through the foregroundColor(Color?) modifier can be filled using the ForegroundShapeStyle() implementation. It is also accessible via dot-syntax as .foreground.

Example

struct ForegroundCircle: View {
    var body: some View {
        Circle()
            .fill(.foreground)
    }
}



struct OtherView: View {
    var body: some View {
        ForegroundCircle()
            .foregroundColor(.green)
    }
}

OtherView will show a green circle.

Tint Color

The value set through the tint(Color?) modifier can be filled using the TintShapeStyle() implementation. It is also accessible via dot-syntax as .tint.

Example

struct TintedCircle: View {
    var body: some View {
        Circle()
            .fill(.tint)
    }
}



struct OtherView: View {
    var body: some View {
        TintedCircle()
            .tint(.orange)
    }
}

OtherView will show an orange circle.