Non penso che tu possa farlo in XML (almeno non in Android), ma ho trovato una buona soluzione pubblicata qui che sembra essere di grande aiuto!
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);
Fondamentalmente, l'array int consente di selezionare più interruzioni di colore e il seguente array float definisce la posizione di tali interruzioni (da 0 a 1). Quindi, come detto, puoi semplicemente usarlo come un Drawable standard.
Modifica: ecco come potresti usarlo nel tuo scenario. Diciamo che hai un pulsante definito in XML in questo modo:
<Button
android:id="@+id/thebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press Me!"
/>
Quindi inseriresti qualcosa del genere nel tuo metodo 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);
Non posso provarlo al momento, questo è il codice dalla mia testa, ma sostanzialmente basta sostituire o aggiungere stop per i colori di cui hai bisogno. Fondamentalmente, nel mio esempio, inizieresti con un verde chiaro, sfumerai in bianco leggermente prima del centro (per dare una dissolvenza, piuttosto che una dura transizione), sfumerai dal bianco al verde medio tra il 45% e il 55%, quindi sfumerai da da metà verde a verde scuro dal 55% alla fine. Potrebbe non apparire esattamente come la tua forma (in questo momento, non ho modo di testare questi colori), ma puoi modificarlo per replicare il tuo esempio.
Modifica: inoltre, si 0, 0, 0, theButton.getHeight()
riferisce alle coordinate x0, y0, x1, y1 del gradiente. Quindi sostanzialmente, inizia con x = 0 (lato sinistro), y = 0 (in alto) e si estende fino a x = 0 (vogliamo un gradiente verticale, quindi non è necessario un angolo da sinistra a destra), y = l'altezza del pulsante. Quindi il gradiente va ad un angolo di 90 gradi dalla parte superiore del pulsante alla parte inferiore del pulsante.
Modifica: Okay, quindi ho un'altra idea che funziona, ahah. In questo momento funziona in XML, ma dovrebbe essere fattibile anche per le forme in Java. È un po 'complesso, e immagino che ci sia un modo per semplificarlo in un'unica forma, ma questo è quello che ho per ora:
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>
Va bene, quindi in pratica ho creato un gradiente di forma in XML per il gradiente verde orizzontale, impostato con un angolo di 0 gradi, passando dal colore verde sinistro dell'area superiore, al colore verde destro. Successivamente, ho creato un rettangolo di forma con un mezzo grigio trasparente. Sono abbastanza sicuro che potrebbe essere incorporato nell'XML dell'elenco dei livelli, ovviando a questo file aggiuntivo, ma non sono sicuro di come. Ma va bene, allora il tipo di parte caotica arriva nel file XML layer_list. Metto il gradiente verde come livello inferiore, quindi metto la mezza sovrapposizione come secondo livello, sfalsando dall'alto di 50dp. Ovviamente vorresti che questo numero fosse sempre la metà di qualunque sia la dimensione della tua vista, e non un fisso di 50dp. Non penso che tu possa usare le percentuali, comunque. Da lì, ho appena inserito un TextView nel mio layout test.xml, usando il file layer_list.xml come sfondo.
Tada!
Ancora una modifica : ho capito che puoi semplicemente incorporare le forme nell'elenco dei livelli come elementi disegnabili, il che significa che non hai più bisogno di 3 file XML separati! Puoi ottenere lo stesso risultato combinandoli così:
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>
Puoi sovrapporre tutti gli elementi che vuoi in questo modo! Potrei provare a giocare e vedere se riesco a ottenere un risultato più versatile tramite Java.
Penso che questa sia l'ultima modifica ... : Va bene, quindi puoi sicuramente correggere il posizionamento tramite Java, come il seguente:
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);
Però! Ciò porta a un altro fastidioso problema in quanto non è possibile misurare TextView fino a quando non è stato disegnato. Non sono ancora sicuro di come puoi farlo ... ma l'inserimento manuale di un numero per topInset funziona.
Ho mentito, un'altra modifica
Bene, ho scoperto come aggiornare manualmente questo layer disegnabile per adattarlo all'altezza del contenitore, la descrizione completa è disponibile qui . Questo codice dovrebbe andare nel tuo metodo 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 ho finito! Meno male! :)