Рувим уже указал на большинство самых полезных наблюдений, поэтому я просто сосредоточусь на реализации этой истории.Существует множество подходов с использованием рефлексии, которые, вероятно, дадут вам то, что вы ищете.
Первый - это (ab) использование частного конструктора GradientDrawable, который принимает ссылку GradientState.К сожалению, последний является последним подклассом с видимостью пакета, поэтому вы не можете легко получить к нему доступ.Для того, чтобы использовать его, вам необходимо углубиться в использование отражения или подражать его функциональности в ваш собственный код.
Второй подход - использовать отражение, чтобы получить закрытую переменную-член mGradientState, которая, к счастью, имеет геттер вформа getConstantState()
.Это даст вам ConstantState, который во время выполнения на самом деле является GradientState, и, следовательно, мы можем использовать отражение для доступа к его членам и изменять их во время выполнения.
Для поддержки приведенных выше утверждений, вот несколько базовая реализациясоздайте рисованный объект в форме кольца из кода:
RingDrawable.java
public class RingDrawable extends GradientDrawable {
private Class<?> mGradientState;
public RingDrawable() {
this(Orientation.TOP_BOTTOM, null);
}
public RingDrawable(int innerRadius, int thickness, float innerRadiusRatio, float thicknessRatio) {
this(Orientation.TOP_BOTTOM, null, innerRadius, thickness, innerRadiusRatio, thicknessRatio);
}
public RingDrawable(GradientDrawable.Orientation orientation, int[] colors) {
super(orientation, colors);
setShape(RING);
}
public RingDrawable(GradientDrawable.Orientation orientation, int[] colors, int innerRadius, int thickness, float innerRadiusRatio, float thicknessRatio) {
this(orientation, colors);
try {
setInnerRadius(innerRadius);
setThickness(thickness);
setInnerRadiusRatio(innerRadiusRatio);
setThicknessRatio(thicknessRatio);
} catch (Exception e) {
// fail silently - change to your own liking
e.printStackTrace();
}
}
public void setInnerRadius(int radius) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
if (mGradientState == null) mGradientState = resolveGradientState();
Field innerRadius = resolveField(mGradientState, "mInnerRadius");
innerRadius.setInt(getConstantState(), radius);
}
public void setThickness(int thicknessValue) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
if (mGradientState == null) mGradientState = resolveGradientState();
Field thickness = resolveField(mGradientState, "mThickness");
thickness.setInt(getConstantState(), thicknessValue);
}
public void setInnerRadiusRatio(float ratio) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
if (mGradientState == null) mGradientState = resolveGradientState();
Field innerRadiusRatio = resolveField(mGradientState, "mInnerRadiusRatio");
innerRadiusRatio.setFloat(getConstantState(), ratio);
}
public void setThicknessRatio(float ratio) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
if (mGradientState == null) mGradientState = resolveGradientState();
Field thicknessRatio = resolveField(mGradientState, "mThicknessRatio");
thicknessRatio.setFloat(getConstantState(), ratio);
}
private Class<?> resolveGradientState() {
Class<?>[] classes = GradientDrawable.class.getDeclaredClasses();
for (Class<?> singleClass : classes) {
if (singleClass.getSimpleName().equals("GradientState")) return singleClass;
}
throw new RuntimeException("GradientState could not be found in current GradientDrawable implementation");
}
private Field resolveField(Class<?> source, String fieldName) throws SecurityException, NoSuchFieldException {
Field field = source.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
}
}
Выше можно использовать следующую процедуру для создания RingDrawable из кода и отображения его в видестандартный ImageView.
ImageView target = (ImageView) findViewById(R.id.imageview);
RingDrawable ring = new RingDrawable(10, 20, 0, 0);
ring.setColor(Color.BLUE);
target.setImageDrawable(ring);
Это покажет простое, непрозрачное синее кольцо в ImageView (внутренний радиус 10 единиц, толщина 20 единиц).Вам нужно убедиться, что вы не установили ширину и высоту ImageView на wrap_content
, если только вы не добавите ring.setSize(width, height)
к коду выше, чтобы он появился.
Надеюсь, это поможет вам в любомспособ.