Формы мульти-градиента
Я хотел бы создать фигуру, которая похожа на следующее изображение:
обратите внимание на верхнюю половину градиентов от цвета 1 до цвета 2, но есть нижняя половина, которая градиентов от цвета 3 до цвета 4. Я знаю, как сделать фигуру с одним градиентом, но я не уверен, как разделить фигуру на две половины и сделать 1 фигуру с 2 различными градиентами.
какие идеи?
5 ответов
Я не думаю, что вы можете сделать это в XML (по крайней мере, не в Android), но я нашел хорошее решение опубликовано здесь похоже, это будет отличная помощь!
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
LinearGradient lg = new LinearGradient(0, 0, width, height,
new int[]{Color.GREEN, Color.GREEN, Color.WHITE, Color.WHITE},
new float[]{0,0.5f,.55f,1}, Shader.TileMode.REPEAT);
return lg;
}
};
PaintDrawable p=new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);
в основном массив int позволяет выбрать несколько цветовых остановок, а следующий массив float определяет, где эти остановки расположены (от 0 до 1). Затем вы можете, как указано, просто использовать это в качестве стандартного Drawable.
Edit: вот как вы можете использовать это в своем сценарии. Давайте скажем, у вас есть кнопка, определенная в XML следующим образом:
<Button
android:id="@+id/thebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press Me!"
/>
затем вы поместите что-то подобное в свой метод onCreate ():
Button theButton = (Button)findViewById(R.id.thebutton);
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
LinearGradient lg = new LinearGradient(0, 0, 0, theButton.getHeight(),
new int[] {
Color.LIGHT_GREEN,
Color.WHITE,
Color.MID_GREEN,
Color.DARK_GREEN }, //substitute the correct colors for these
new float[] {
0, 0.45f, 0.55f, 1 },
Shader.TileMode.REPEAT);
return lg;
}
};
PaintDrawable p = new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);
theButton.setBackground((Drawable)p);
Я не могу проверить это на данный момент, это код из моей головы, но в основном просто замените или добавьте остановки для цветов, которые вам нужны. В принципе, в моем примере вы начнете со светло-зеленого, немного выцветете до белого цвета перед центром (чтобы дать выцветание, а не резкий переход), исчезнете с белого до среднего зеленого между 45% и 55%, затем выцветают от среднего зеленого до темно-зеленого от 55% до конца. Это может выглядеть не совсем так, как ваша форма (сейчас у меня нет возможности проверить эти цвета), но вы можете изменить это, чтобы повторить свой пример.
Edit: кроме того,0, 0, 0, theButton.getHeight()
относится к координатам x0, y0, x1, y1 градиента. Таким образом, в основном, он начинается с x = 0 (левая сторона), y = 0 (вверху) и тянется до x = 0 (нам нужен вертикальный градиент, поэтому не требуется левый и правый угол), y = высота кнопка. Таким образом, градиент идет под углом 90 градусов от верхней части кнопки к нижней части кнопки.
Edit: хорошо, у меня есть еще одна идея, которая работает, ха-ха. Прямо сейчас он работает в XML, но должен быть выполним для фигур в Java. Это своего рода комплекс, и я думаю, что есть способ упростить его в единую форму, но это то, что у меня есть для теперь:
green_horizontal_gradient.в XML
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners
android:radius="3dp"
/>
<gradient
android:angle="0"
android:startColor="#FF63a34a"
android:endColor="#FF477b36"
android:type="linear"
/>
</shape>
half_overlay.в XML
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<solid
android:color="#40000000"
/>
</shape>
layer_list.в XML
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item
android:drawable="@drawable/green_horizontal_gradient"
android:id="@+id/green_gradient"
/>
<item
android:drawable="@drawable/half_overlay"
android:id="@+id/half_overlay"
android:top="50dp"
/>
</layer-list>
! Это приводит к еще одной неприятной проблеме в том, что вы невозможно измерить TextView до тех пор, пока он не будет нарисован. Я пока не совсем понимаю, как вы можете это сделать...но ручная вставка номера для topInset действительно работает.
я соврал, еще одно редактирование
хорошо, узнал, как вручную обновить этот слой drawable, чтобы соответствовать высоте контейнера, полное описание можно найти здесь. Этот код должен идти в вашем методе onCreate ():
final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
LayerDrawable ld = (LayerDrawable)tv.getBackground();
ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
}
});
и я сделал! Уфф! :)
вы можете наложить градиентные фигуры в xml с помощью списка слоев. Представьте себе кнопку с состоянием по умолчанию, как показано ниже, где второй элемент полупрозрачен. Это добавляет своего рода виньетирование. (Пожалуйста, извините за пользовательские цвета.)
<!-- Normal state. -->
<item>
<layer-list>
<item>
<shape>
<gradient
android:startColor="@color/grey_light"
android:endColor="@color/grey_dark"
android:type="linear"
android:angle="270"
android:centerColor="@color/grey_mediumtodark" />
<stroke
android:width="1dp"
android:color="@color/grey_dark" />
<corners
android:radius="5dp" />
</shape>
</item>
<item>
<shape>
<gradient
android:startColor="#00666666"
android:endColor="#77666666"
android:type="radial"
android:gradientRadius="200"
android:centerColor="#00666666"
android:centerX="0.5"
android:centerY="0" />
<stroke
android:width="1dp"
android:color="@color/grey_dark" />
<corners
android:radius="5dp" />
</shape>
</item>
</layer-list>
</item>
вы можете сделать это, используя только XML-формы-просто используйте layer-list и отрицательное заполнение, как это:
<layer-list>
<item>
<shape>
<solid android:color="#ffffff" />
<padding android:top="20dp" />
</shape>
</item>
<item>
<shape>
<gradient android:endColor="#ffffff" android:startColor="#efefef" android:type="linear" android:angle="90" />
<padding android:top="-20dp" />
</shape>
</item>
</layer-list>
вы пытались наложить один градиент с почти прозрачной непрозрачностью для выделения поверх другого изображения с непрозрачной непрозрачностью для зеленого градиента?
попробуйте этот метод, тогда вы можете делать все, что хотите.
Это как стек поэтому будьте осторожны, какой элемент приходит первым или последним.
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="50dp" android:start="10dp" android:left="10dp">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="#012d08"/>
</shape>
</item>
<item android:top="50dp">
<shape android:shape="rectangle">
<solid android:color="#7c4b4b" />
</shape>
</item>
<item android:top="90dp" android:end="60dp">
<shape android:shape="rectangle">
<solid android:color="#e2cc2626" />
</shape>
</item>
<item android:start="50dp" android:bottom="20dp" android:top="120dp">
<shape android:shape="rectangle">
<solid android:color="#360e0e" />
</shape>
</item>