Je ne pense pas que vous puissiez le faire en XML (du moins pas sous Android), mais j'ai trouvé une bonne solution publiée ici qui semble être d'une grande aide!
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);
Fondamentalement, le tableau int vous permet de sélectionner plusieurs arrêts de couleur, et le tableau flottant suivant définit où ces arrêts sont positionnés (de 0 à 1). Vous pouvez ensuite, comme indiqué, simplement l'utiliser comme un Drawable standard.
Edit: Voici comment vous pouvez utiliser cela dans votre scénario. Disons que vous avez un bouton défini en XML comme ceci:
<Button
android:id="@+id/thebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press Me!"
/>
Vous mettriez ensuite quelque chose comme ça dans votre méthode 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);
Je ne peux pas tester cela pour le moment, c'est du code de ma tête, mais en gros, remplacez ou ajoutez des arrêts pour les couleurs dont vous avez besoin. Fondamentalement, dans mon exemple, vous commenceriez par un vert clair, un fondu au blanc légèrement avant le centre (pour donner un fondu, plutôt qu'une transition dure), un fondu du blanc au vert moyen entre 45% et 55%, puis un fondu de vert moyen à vert foncé de 55% à la fin. Cela peut ne pas ressembler exactement à votre forme (pour le moment, je n'ai aucun moyen de tester ces couleurs), mais vous pouvez le modifier pour reproduire votre exemple.
Edit: En outre, le 0, 0, 0, theButton.getHeight()
fait référence aux coordonnées x0, y0, x1, y1 du dégradé. Donc, fondamentalement, cela commence à x = 0 (côté gauche), y = 0 (en haut) et s'étire jusqu'à x = 0 (nous voulons un dégradé vertical, donc aucun angle de gauche à droite n'est nécessaire), y = la hauteur du bouton. Ainsi, le dégradé va à un angle de 90 degrés du haut du bouton au bas du bouton.
Edit: D'accord, j'ai donc une autre idée qui fonctionne, haha. À l'heure actuelle, cela fonctionne en XML, mais devrait également être faisable pour les formes en Java. C'est un peu complexe, et j'imagine qu'il existe un moyen de le simplifier en une seule forme, mais c'est ce que j'ai pour le moment:
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>
D'accord, j'ai donc créé un dégradé de forme en XML pour le dégradé vert horizontal, défini à un angle de 0 degré, allant de la couleur verte gauche de la zone supérieure à la couleur verte droite. Ensuite, j'ai fait un rectangle de forme avec un gris semi-transparent. Je suis presque sûr que cela pourrait être intégré dans le XML de la liste de couches, évitant ce fichier supplémentaire, mais je ne sais pas comment. Mais d'accord, alors le genre de partie piratée entre dans le fichier XML layer_list. J'ai mis le dégradé vert comme couche inférieure, puis la demi-superposition comme deuxième couche, décalée du haut de 50dp. De toute évidence, vous voudriez que ce nombre soit toujours la moitié de la taille de votre vue, et non un 50dp fixe. Je ne pense pas que vous puissiez utiliser des pourcentages, cependant. À partir de là, je viens d'insérer un TextView dans ma mise en page test.xml, en utilisant le fichier layer_list.xml comme arrière-plan.
Tada!
Une dernière modification : j'ai réalisé que vous pouvez simplement incorporer les formes dans la liste des calques dessinables en tant qu'éléments, ce qui signifie que vous n'avez plus besoin de 3 fichiers XML séparés! Vous pouvez obtenir le même résultat en les combinant comme ceci:
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>
Vous pouvez superposer autant d'éléments que vous le souhaitez de cette façon! Je peux essayer de jouer et voir si je peux obtenir un résultat plus polyvalent grâce à Java.
Je pense que c'est la dernière modification ... : D'accord, vous pouvez donc définitivement corriger le positionnement via Java, comme suit:
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);
Toutefois! Cela conduit à un autre problème ennuyeux en ce que vous ne pouvez pas mesurer le TextView avant qu'il n'ait été dessiné. Je ne sais pas encore comment vous pouvez accomplir cela ... mais l'insertion manuelle d'un numéro pour topInset fonctionne.
J'ai menti, encore une modification
OK, découvrez comment mettre à jour manuellement cette couche dessinable pour qu'elle corresponde à la hauteur du conteneur, une description complète peut être trouvée ici . Ce code devrait aller dans votre méthode 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);
}
});
Et j'ai fini! Ouf! :)