Android: How to draw a two dimensional gradient

2019-05-29 22:10发布

问题:

I am looking to draw a gradient like this using Android's Canvas:

In the horizontal direction there is a gradient of two colors (red and blue). Then in the vertical direction there is a gradient of transparency (allowing the red and blue to show) to nothing (the absence of all color?).

I found this link on SO here which is close to what I want. But I cannot figure out how to make the bottom transparent.

How can this be accomplished in Android?

回答1:

Those sort of "custom" gradients can sometimes be pretty annoying. To make it as painless as you can, you could use specially prepared drawable resource.

There are two main ways you can accomplish that with a drawable:

  1. Use two linear gradients
  2. Use two radial gradients

The first approach could be implemented like this:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <gradient
                android:angle="315"
                android:centerColor="#4DFC0A00"
                android:endColor="#00FC0A00"
                android:startColor="#FC0A00" />
        </shape>
    </item>
    <item>
        <shape>
            <gradient
                android:angle="225"
                android:centerColor="#4D5E17FD"
                android:endColor="#005E17FD"
                android:startColor="#5E17FD" />
        </shape>
    </item>
</layer-list>

And it would look like this (presented on white background):

You could still twitch centerX and centerY values for those gradients (defaults are 0.5)

The second approach could be implemented like this:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <gradient
                android:centerX="0"
                android:centerY="0"
                android:gradientRadius="@dimen/gradient_width"
                android:endColor="#00FC0A00"
                android:centerColor="#80FC0A00"
                android:startColor="#FC0A00"
                android:type="radial" />
        </shape>
    </item>
    <item>
        <shape>
            <gradient
                android:centerX="1"
                android:centerY="0"
                android:gradientRadius="@dimen/gradient_width"
                android:endColor="#005E17FD"
                android:centerColor="#805E17FD"
                android:startColor="#5E17FD"
                android:type="radial" />
        </shape>
    </item>
</layer-list>

And it would look like this (presented on white background):

The one downside of the second approach is that you need to know your gradient width to set the gradientRadius.

You can also not set the gradientRadius to the full width, but like a 75% of it. It will give it a nice overlap but not too much.



回答2:

Here's how to draw it in Skia using C++. The equivalent in Java on Android should be very similar.

SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
SkPoint horz[] = { { 0, 0 }, { 256, 0 } };
SkPaint paint;
paint.setShader(SkGradientShader::MakeLinear(horz, colors, nullptr, 2,
        SkShader::kClamp_TileMode));
canvas->drawPaint(paint);
paint.setBlendMode(SkBlendMode::kDstIn);
SkColor alphas[] = { SK_ColorBLACK, SK_ColorTRANSPARENT };
SkPoint vert[] = { { 0, 0 }, { 0, 256 } };
paint.setShader(SkGradientShader::MakeLinear(vert, alphas, nullptr, 2,
        SkShader::kClamp_TileMode));
canvas->drawPaint(paint);

gradient with fade