Search code examples
iosswiftswiftuigradient

Is it possible to add "Weights" to the colors in a SwiftUI Gradient?


I am using a color gradient as the background for my app (in SwiftUI). It is super simple and looks something like this

To do this, I have just set the background to a linear color gradient like this (abbreviated):

private var grade = Gradient(colors: [Color("Red"), Color("Blue")])

...

.background(LinearGradient(gradient: grade, startPoint: .top, endPoint: .bottom))

I want the gradient to be 'red-shifted' when the user increases the number in the circle (by dragging the little circle), and be 'blue-shifted' when it is a lower number.

One thing I have tried is setting the colors to a very large array, starting with half being Color("Red"), and half Color("Blue"); then I thought I could change the number of red as the user drags; however, this also decreases the amount of gradient applied (it looks much more like a red box and a blue box then a gradient). It does work on a smaller scale though, so I set the colors to [Color("Red"), Color("Red"), Color("Blue")] to show what I might want it to look like at a larger number:

enter image description here

I would like this effect to be continuous (or effectively continuous) though.

I hope this demonstrates what I am trying to achieve, and as always, thanks for the help!


Solution

  • Here is possible solution. Tested with Xcode 11.4 / iOS 13.4

    Note: of course parameters can be modified for your needs

    demo

    struct DemoGradientShift: View {
        private var grade = Gradient(colors: [.red, .blue])
        @State private var value: CGFloat = 50
        var body: some View {
            ZStack {
                VStack {
                    Rectangle().fill(Color.red)
                    Rectangle().fill(Color.blue)
                }
                Rectangle().fill(LinearGradient(gradient: grade, startPoint: .top, endPoint: .bottom))
                    .offset(x: 0, y: 5 * (50 - value))
                Slider(value: $value, in: 1...100)
            }
            .edgesIgnoringSafeArea(.all)
        }
    }