Gradient Radius as percentage of screen size
Asked Answered
H

5

35

I'm trying to create a shape drawable with radial gradient background, with radius that will adjust to the screen size (take a look at the relevant documentation).

This is my code:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <gradient
        android:endColor="#000"
        android:gradientRadius="50%p"
        android:startColor="#5d2456"
        android:type="radial" />
</shape>

But it doens't seem to work. if I remove the "%p", it works, but then the radius will be static, thus not adjusting to the screen size...Any idea what's wrong?

Halfbaked answered 24/6, 2012 at 10:10 Comment(4)
gradientRadius is a property that is based on an integer value. Putting a percent or any kind of measurement value won't work. I know this isn't the answer you're looking for but at least it will help narrow down what you're looking for.Stinger
Same problem here (at least when previewing my layout in Eclipse): the gradient is not applied if the radius is specified with % or %pMunger
The worst part is, it doesn't work even if I have an integer resource defined elsewhere, and refer that here (@integer/gradientRadius). It seems to accept only absolute hard-coded integers.Comet
Percentages are not supported for android's dimension values. It has been made clear before: groups.google.com/forum/#!msg/android-developers/EZL4n2mrpds/…Doris
E
12

From what I´ve tested, the % does work, but not as you expected.
First of all

android:gradientRadius="50"

seems to take the value as pixels 50px

android:gradientRadius="50%"

is converted as if 50% = 0.5 px, try

android:gradientRadius="5000%"

and you will see a 50px radius.
Using %p has a similar result. Obviously this is something I hope will be changed in the future, because it does not have much use as it is. Usually XML ShapeDrawable resources adapt their size to some external container, in this case gradientRadius is setting the size regardless of the container.

Exaggerative answered 25/7, 2013 at 15:3 Comment(2)
"50000%p" is the same as "50", as ilomambo said before, so if you want some readability you shouldn't use it.Pizor
A better solution will be to use values-mdpi, values-hdpi folders and provide different dimen values and refer to them in the radius value field.Paramour
S
9

I ended up creating a custom View with following overriden onDraw method:

@Override
protected void onDraw(Canvas canvas) {
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    int maxSize = Math.max(getHeight(), getWidth());
    RadialGradient gradient = new RadialGradient(
            getWidth()/2,
            getHeight()/2,
            maxSize, 
            new int[] {Color.RED, Color.BLACK},
            new float[] {0, 1}, 
            android.graphics.Shader.TileMode.CLAMP);

    paint.setDither(true);
    paint.setShader(gradient);

    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
}

In your layout just add the View:

<yourpackage.GradientView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Of course it would be possible to create attributes for the View, eg. color, percentage to allow customization via XML.

Shipley answered 6/7, 2013 at 14:52 Comment(0)
C
5

Note that gradientRadius percentages do work in Lollipop. But if you have to support pre-Lollipop I expanded upon @marnaish's answer adding XML attributes. My gradientRadius is defined as a percentage of the parent view's width:

public class RadialGradientView extends View {
    private final int endColor;
    private final int startColor;
    private final float gradientRadiusWidthPercent;
    private final float centerY;
    private final float centerX;
    private Paint paint;

    public RadialGradientView(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RadialGradientView, 0, 0);

        startColor = a.getColor(R.styleable.RadialGradientView_startColor, Color.RED);
        endColor = a.getColor(R.styleable.RadialGradientView_endColor, Color.BLACK);
        gradientRadiusWidthPercent = a.getFloat(R.styleable.RadialGradientView_gradientRadiusWidthPercent, 1);
        centerX = a.getFloat(R.styleable.RadialGradientView_centerX, .5f);
        centerY = a.getFloat(R.styleable.RadialGradientView_centerY, .5f);

        a.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        RadialGradient gradient = new RadialGradient(
                parentWidth*centerX,
                parentHeight*centerY,
                parentWidth*gradientRadiusWidthPercent,
                new int[] {startColor, endColor},
                null,
                android.graphics.Shader.TileMode.CLAMP);

        paint.setDither(true);
        paint.setShader(gradient);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
    }

}

In attrs.xml:

<declare-styleable name="RadialGradientView">
    <attr name="startColor" format="color|reference"/>
    <attr name="endColor" format="color|reference"/>
    <attr name="gradientRadiusWidthPercent" format="float"/>
    <attr name="centerX" format="float"/>
    <attr name="centerY" format="float"/>
</declare-styleable>

Unfortunately you can't create an XML drawable from a custom class, so you can't set it as a View's android:background. The workaround is to use a FrameLayout to layer it as the background.

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="100dp">

    <com.RadialGradientView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:centerX=".3"
        app:centerY=".5"
        app:endColor="#0f0"
        app:startColor="#f00"
        app:gradientRadiusWidthPercent=".5"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="What's up world?"/>
</FrameLayout>
Complected answered 3/3, 2015 at 1:6 Comment(0)
B
0

You could create a shape drawable at runtime similiar to this post https://mcmap.net/q/450530/-changing-gradient-background-colors-on-android-at-runtime

This way you could calculate the percentage after retrieving the screen size.

Brilliancy answered 12/9, 2012 at 2:43 Comment(0)
L
0

It's impossible to set a shape corner radius expressed in percentage in a drawable xml.

Lapierre answered 1/3, 2019 at 16:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.