Não acho que você possa fazer isso em XML (pelo menos não no Android), mas encontrei uma boa solução postada aqui que parece ser uma grande ajuda!
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);
Basicamente, a matriz int permite selecionar várias paradas de cores, e a seguinte matriz flutuante define onde essas paradas são posicionadas (de 0 a 1). Você pode, como indicado, usar isso como um Drawable padrão.
Editar: veja como você pode usar isso no seu cenário. Digamos que você tenha um botão definido em XML da seguinte forma:
<Button
android:id="@+id/thebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press Me!"
/>
Você colocaria algo assim no método 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);
Não posso testar isso no momento, esse é o código da minha cabeça, mas basicamente basta substituir ou adicionar paradas para as cores que você precisa. Basicamente, no meu exemplo, você começaria com um verde claro, desbotaria levemente para o branco antes do centro (para dar uma desbotamento, em vez de uma transição severa), desbotaria do branco para o verde médio entre 45% e 55% e depois desbotaria verde médio a verde escuro de 55% até o final. Isso pode não parecer exatamente com sua forma (no momento, não tenho como testar essas cores), mas você pode modificá-lo para replicar seu exemplo.
Editar: Além disso, 0, 0, 0, theButton.getHeight()
refere-se às coordenadas x0, y0, x1, y1 do gradiente. Então, basicamente, começa em x = 0 (lado esquerdo), y = 0 (em cima) e se estende até x = 0 (estamos querendo um gradiente vertical, portanto, nenhum ângulo da esquerda para a direita é necessário), y = a altura do botão Portanto, o gradiente vai em um ângulo de 90 graus, da parte superior do botão até a parte inferior do botão.
Edit: Ok, então eu tenho mais uma idéia que funciona, haha. No momento, ele funciona em XML, mas também deve ser possível para formas em Java. É meio complexo, e imagino que há uma maneira de simplificá-lo em uma única forma, mas é isso que tenho por enquanto:
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>
test.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
>
<TextView
android:id="@+id/image_test"
android:background="@drawable/layer_list"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:text="Layer List Drawable!"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="26sp"
/>
</RelativeLayout>
Ok, basicamente criei um gradiente de forma em XML para o gradiente horizontal verde, definido em um ângulo de 0 grau, passando da cor verde esquerda da área superior para a cor verde direita. Em seguida, fiz um retângulo de forma com um meio cinza transparente. Tenho certeza de que isso pode estar embutido no XML da lista de camadas, evitando esse arquivo extra, mas não sei como. Mas tudo bem, então o tipo de parte hacky entra no arquivo XML layer_list. Coloquei o gradiente verde como camada inferior e depois coloque a meia sobreposição como segunda camada, deslocada do topo em 50dp. Obviamente, você deseja que esse número seja sempre metade do tamanho da visualização, e não 50dp fixo. Eu acho que você não pode usar porcentagens. A partir daí, eu apenas inseri um TextView no meu layout test.xml, usando o arquivo layer_list.xml como plano de fundo.
Tada!
Mais uma edição : eu percebi que você pode incorporar as formas na lista de camadas que podem ser desenhadas como itens, o que significa que você não precisa mais de 3 arquivos XML separados! Você pode obter o mesmo resultado combinando-os da seguinte forma:
layer_list.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item>
<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>
</item>
<item
android:top="50dp"
>
<shape
android:shape="rectangle"
>
<solid
android:color="#40000000"
/>
</shape>
</item>
</layer-list>
Você pode colocar em camadas quantos itens quiser dessa maneira! Eu posso tentar brincar e ver se consigo um resultado mais versátil através do Java.
Acho que esta é a última edição ... : Ok, então você pode definitivamente corrigir o posicionamento através de Java, como o seguinte:
TextView tv = (TextView)findViewById(R.id.image_test);
LayerDrawable ld = (LayerDrawable)tv.getBackground();
int topInset = tv.getHeight() / 2 ; //does not work!
ld.setLayerInset(1, 0, topInset, 0, 0);
tv.setBackgroundDrawable(ld);
Contudo! Isso leva a outro problema irritante, pois você não pode medir o TextView até que ele tenha sido desenhado. Ainda não tenho certeza de como você pode fazer isso ... mas inserir manualmente um número para topInset funciona.
Eu menti, mais uma edição
Ok, descobri como atualizar manualmente essa camada desenhável para corresponder à altura do contêiner, descrição completa pode ser encontrada aqui . Este código deve ir no seu método 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);
}
});
E eu terminei! Uau! :)