问题
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?
回答1:
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.
回答2:
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.
回答3:
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>
回答4:
You could create a shape drawable at runtime similiar to this post https://stackoverflow.com/a/4943888/604504
This way you could calculate the percentage after retrieving the screen size.
回答5:
It's impossible to set a shape corner radius expressed in percentage in a drawable xml.
来源:https://stackoverflow.com/questions/11176590/gradient-radius-as-percentage-of-screen-size