skip to Main Content

Been trying to find a solution to dynamically detect the Background Color / the color underneath the View you want to modify, since I may want to have readable text over a Image without resorting to using an average color of a Image to determine the right color for the text because some images may have more light colours in certain places in a Image, vice versa with Dark Colors, so is there a way to get the color at a certain Coord then use that to determine what the Text Color should be, tried using Grok etc to generate a basis which got me so far but there isn’t a Color function in the GeomertyReader since it wants me to use that Response from Grok.

struct BackgroundColorKey: PreferenceKey {
    static var defaultValue: Color? = nil
    
    static func reduce(value: inout Color?, nextValue: () -> Color?) {
        value = nextValue()
    }
}

struct BackgroundColorReader: View {
    var body: some View {
        GeometryReader { geometry in
            Color.clear
                .preference(key: BackgroundColorKey.self, value: geometry.color(at: geometry.frame(in: .local).center))
        }
    }
}

struct DynamicTextColor: View {
    @State private var backgroundColor: Color? = nil
    
    var body: some View {
        VStack {
            Text("Your Text Here")
                .foregroundColor(backgroundColor?.luminance < 0.5 ? .white : .black) // Invert based on luminance
                .background(
                    BackgroundColorReader()
                        .onPreferenceChange(BackgroundColorKey.self) { newColor in
                            self.backgroundColor = newColor
                        }
                )
        }
    }
}

That’s the Code it generated, also looked endlessly online if someone else had a solution nothing, so is there a Framework or a solution that could be used for both macOS & iOS.

This is an Example I’m trying to solve in SwiftUI I have Below

This is an Example I'm trying to solve in SwiftUI

2

Answers


  1. try this:

    ZStack {
        wallpaper
    
        ZStack {
            text.foregroundColor(.white)
                .blendMode(.difference)
                .overlay(text.blendMode(.hue))
                .overlay(text.foregroundColor(.white).blendMode(.overlay))
                .overlay(text.foregroundColor(.black).blendMode(.overlay))
        }
    }
    

    result:

    enter image description here

    Code taken from: https://designcode.io/swiftui-handbook-multiple-blending-modes


    IMHO: Better to do not use color inversion / blending.

    Better to do outline effect around text. (black text – white outline OR white text – black outline.)

    enter image description here

    Login or Signup to reply.
  2. When you use .blendMode it effectively examines the image on a pixel-by-pixel basis for you. Some notes:

    • The documentation for the enum BlendMode is basic, to say the least. However, you will find better documentation for the different modes under GraphicsContext.BlendMode.

    • Use .compositingGroup() to limit the scope with which the blend mode works. In particular, this can be used to stop it from going to lower layers, or for combining different blend mode effects.

    Here is an example based on your sample image:

    Image("BaseImage")
        .resizable()
        .scaledToFit()
        .overlay(alignment: .topLeading) {
            Text(text)
                .foregroundStyle(.white)
                .blendMode(.difference)
        }
        .overlay(alignment: .topLeading) {
            Text(text)
                .foregroundStyle(.white)
                .blendMode(.softLight)
        }
        .compositingGroup()
    

    Screenshot

    If you really want to do the image analysis yourself, this answer shows how to get the color values at a particular pixel position.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search