Formes multi-gradient

Je voudrais créer une forme qui ressemble à l'image suivante:

le texte d'alt

Notez les dégradés de la moitié supérieure de la couleur 1 à la couleur 2, mais il y a une moitié inférieure qui gradients de la couleur 3 à la couleur 4. Je sais comment faire une forme avec un seul dégradé, mais je ne sais pas comment diviser une forme en deux moitiés et faire 1 forme avec 2 dégradés différents.

Des idées?

170
demandé sur Andrew 2010-12-07 23:04:10

5 réponses

Je ne pense pas que vous puissiez le faire en XML (du moins pas dans Android), mais j'ai trouvé une bonne solution postée ici {[13] } 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 float 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 l'utiliser dans votre scénario. Disons que vous avez un bouton défini en XML comme suit:

<Button
    android:id="@+id/thebutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Press Me!"
    />

Vous mettriez alors quelque chose comme ceci 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 fondamentalement, il suffit de remplacer, ou d'ajouter des arrêts pour les couleurs dont vous avez besoin. Fondamentalement, dans mon exemple, vous commenceriez par un vert clair, fondu au blanc légèrement avant le centre (pour donner un fondu, plutôt qu'une transition dure), fondu du blanc au vert moyen entre 45% et 55%, puis fondu du vert moyen au foncé vert de 55% à la fin. Cela peut ne pas ressembler exactement à votre forme (en ce moment, je n'ai aucun moyen de tester ces couleurs), mais vous pouvez modifier cela pour répliquer votre exemple.

Edit: en outre, le 0, 0, 0, theButton.getHeight() fait référence aux coordonnées x0, y0, x1, y1 du gradient. Donc, fondamentalement, il commence à x = 0( côté gauche), y = 0 (en haut), et s'étend à x = 0 (nous voulons un gradient vertical, donc aucun angle gauche à droite n'est nécessaire), y = la hauteur du bouton. Donc le gradient va à un angle de 90 degrés du haut du bouton au bas du bouton.

Edit: Ok, donc j'ai une idée de plus qui fonctionne, haha. En ce moment, il fonctionne en XML, mais devrait être faisable pour les formes en Java. C'est un peu complexe, et j'imagine qu'il y a un moyen de le simplifier en une seule forme, mais c'est ce que j'ai pour maintenant:

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, donc fondamentalement, j'ai 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 à moitié transparent. Je suis assez sûr que pourrait être intégré dans la liste de calques XML, évitant ce fichier supplémentaire,mais je ne sais pas comment. Mais bon, alors le genre de partie hacky vient dans le fichier XML layer_list. J'ai mis le dégradé vert comme couche inférieure, puis mis la demi-superposition comme deuxième couche, décalée du haut de 50dp. Évidemment, 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 pouvez utiliser des pourcentages, cependant. De là, je viens d'insérer un TextView dans mon test.XML mise en page, en utilisant la layer_list.fichier xml, comme mon arrière-plan. J'ai mis la hauteur à 100dp (deux fois la taille du décalage de la superposition), ce qui entraîne ce qui suit:

le texte d'alt

Tada!

Encore une édition : j'ai réalisé que vous pouvez simplement intégrer 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 suit:

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 couche 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 via Java.

Je pense que c'est la dernière édition...: Ok, donc vous pouvez certainement 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);

Cependant! Cela conduit à un autre problème ennuyeux en ce sens que vous ne pouvez pas mesurer le TextView jusqu'à ce qu'il ait été dessiné. Je ne sais pas encore comment vous pouvez accomplir cela...mais en insérant manuellement un nombre pour topInset fonctionne.

J'ai menti, encore une édition

Ok, trouvé comment mettre à jour manuellement cette couche dessinés à la hauteur du conteneur, 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! :)

364
répondu kcoppock 2017-10-15 18:20:59

Vous pouvez calquer des formes de dégradé dans le xml à l'aide d'une liste de calques. Imaginez un bouton avec l'état par défaut comme ci-dessous, où le deuxième élément est semi-transparent. Il ajoute une sorte de vignettage. (Veuillez excuser les couleurs personnalisées.)

<!-- 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>

25
répondu LordParsley 2012-08-12 15:29:53

Vous pouvez le faire en utilisant uniquement des formes xml - utilisez simplement la liste des calques et le remplissage négatif comme ceci:

    <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>
2
répondu konmik 2014-06-24 13:32:07

Avez-vous essayé de superposer un dégradé avec une opacité presque transparente pour la surbrillance au-dessus d'une autre image avec une opacité opaque pour le dégradé vert?

1
répondu Greg D 2010-12-07 20:12:33

Essayez cette méthode alors vous pouvez faire tout ce que vous voulez.
C'est comme une pile {[4] } alors faites attention à l'élément qui vient en premier ou en dernier.

<?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>

0
répondu Khalid Ali 2017-11-02 17:08:11