I wanted to use a linear gradient, like for exampl...
# compose
s
I wanted to use a linear gradient, like for example
Copy code
Brush.horizontalGradient(
 0.9f to Color.Black,
 1f to Color.Transparent,
)
But I also wanted to if possible be able to pass an
Easing
regarding how that section between 0.9f and 1.0f will progress. Right now it does a linear change from Black to Transparent, but is there a way for me to give it just an
Easing
in there, or would I need to "hack" it by doing something like
Copy code
Brush.horizontalGradient(
 0.9f to Color.Black,
 0.92f to figureThisOutMyself(),
 0.94f to figureThisOutMyself(),
 0.96f to figureThisOutMyself(),
 0.98f to figureThisOutMyself(),
 1f to Color.Transparent,
)
And just play with it until it stops feeling choppy? The use case is to do something like this but the way that the fade happens linearly looks not so nice in some scenarios.
Haze seems to be doing exactly that here but this looks completely custom to their implementation of course. I wonder if there's something like this available already in the compose APIs that I am missing
Aha well they do this:
Copy code
internal fun HazeProgressive.LinearGradient.asBrush(numStops: Int = 20): Brush {
  return Brush.linearGradient(
    colors = List(numStops) { i ->
      val x = i * 1f / (numStops - 1)
      Color.Black.copy(alpha = lerp(startIntensity, endIntensity, easing.transform(x)))
    },
    start = start,
    end = end,
  )
}
Perhaps that is the way indeed, make enough stops where this feels good enough, but in reality you are still using normal linear scaling in-between these stops
y
I think the issue you'll face is on Android Compose is just exposing existing non-compose Brush, which are basically the feature spec.
So effectively this is the feature spec
Copy code
public class LinearGradient extends Shader {
    private float mX0;
    private float mY0;
    private float mX1;
    private float mY1;
    private float[] mPositions;
    private TileMode mTileMode;

...

    @ColorLong
    private final long[] mColorLongs;
s
Yup makes sense, thanks for the links! So my best bet, if anything, is to try to emulate this with doing many color-stops, exactly like haze does right? And just do a trial and error around how many stops are enough to make my easing look good enough. Do you agree with that idea?
y
Yeah, I think you could measure the difference with math, and get something that you know is basically the same visually with minimal points.
thank you color 1
👍 1
r
There's no need for trial and error, you can compute how many points are needed. What you basically need to do is "flatten" the curve using a threshold of 1/(x*length) where length is the length of the gradient in pixels and x is the resolution you want
I would just write a custom shader or generate a bitmap
(we provide APIs for flattening btw)
s
I must admit I am not familiar with them, is there something you could link me to so I can read more about it myself?
r
“Them” being…?
If it’s path flattening, you can use
thePath.asAndroidPath().approximate()
(https://developer.android.com/reference/android/graphics/Path.html#approximate(float))
There’s an easier to use version in androidx-core-ktx
but that’s why a shader would be easier
you would “just” evaluate the curve in the shader to compute the color at a given point
s
"Them" meant "those APIs" in that message, sorry for being unclear. Thanks for the links there! Regarding the suggestion of shaders here, aren't those only android 13 and onwards? It'd be excluding a ton of users if so. I've never written anything with shaders myself, and it's a bit hard to get into when I know I practically shouldn't use them yet, since the fallback for all the rest of the users is that the shader just does nothing right? Am I misunderstanding this somehow?
r
Yeah you can’t use custom shaders before API 33
But before API 33 you could use a regular gradient or emulate it with color stops