34 votes

Rayon du dégradé en pourcentage de la taille de l'écran

J'essaie de créer une forme traçable avec un arrière-plan à gradient radial, dont le rayon s'ajuste à la taille de l'écran (voir l'image correspondante). documentation ).

Voici mon code :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <gradient
        android:endColor="#000"
        android:gradientRadius="50%p"
        android:startColor="#5d2456"
        android:type="radial" />
</shape>

Mais cela ne semble pas fonctionner. Si j'enlève le "%p", cela fonctionne, mais le rayon sera alors statique, ne s'adaptant pas à la taille de l'écran... Une idée de ce qui ne va pas ?

0 votes

GradientRadius est une propriété qui se base sur une valeur entière. L'insertion d'un pourcentage ou de toute autre valeur de mesure ne fonctionnera pas. Je sais que ce n'est pas la réponse que vous cherchez, mais au moins cela vous aidera à préciser ce que vous recherchez.

0 votes

Même problème ici (du moins lorsque je prévisualise ma mise en page dans Eclipse) : le dégradé n'est pas appliqué si le rayon est spécifié avec % o %p

0 votes

Le pire, c'est que cela ne fonctionne pas, même si j'ai une ressource entière définie ailleurs, et que je m'y réfère ici (@integer/gradientRadius). Il semble qu'il n'accepte que les entiers absolus codés en dur.

12voto

ilomambo Points 2860

D'après ce que j'ai testé, le % fonctionne, mais pas comme vous le pensiez.
Tout d'abord

android:gradientRadius="50"

semble prendre la valeur de pixels 50px

android:gradientRadius="50%"

est converti comme si 50% = 0.5 px, essayez

android:gradientRadius="5000%"

et vous verrez un rayon de 50px.
Utilisation de %p donne un résultat similaire. Il s'agit évidemment d'un élément qui, je l'espère, sera modifié à l'avenir, car il n'est pas très utile tel qu'il est. Habituellement, les ressources XML ShapeDrawable adaptent leur taille à un conteneur externe, dans ce cas-ci gradientRadius est de définir la taille indépendamment du conteneur.

7 votes

"50000%p" est identique à "50", comme ilomambo l'a déjà dit, donc si vous voulez une certaine lisibilité, vous ne devriez pas l'utiliser.

3 votes

Une meilleure solution serait d'utiliser les dossiers values-mdpi, values-hdpi et de fournir différentes valeurs de dimen et de s'y référer dans le champ de valeur du rayon.

9voto

marnaish Points 1226

J'ai fini par créer une vue personnalisée avec la méthode onDraw surchargée suivante :

@Override
protected void onDraw(Canvas canvas) {
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    int maxSize = Math.max(getHeight(), getWidth());
    RadialGradient gradient = new RadialGradient(
            getWidth()/2,
            getHeight()/2,
            maxSize, 
            new int[] {Color.RED, Color.BLACK},
            new float[] {0, 1}, 
            android.graphics.Shader.TileMode.CLAMP);

    paint.setDither(true);
    paint.setShader(gradient);

    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
}

Dans votre mise en page, ajoutez simplement la vue :

<yourpackage.GradientView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Bien sûr, il serait possible de créer des attributs pour la vue, par exemple la couleur, le pourcentage pour permettre la personnalisation via XML.

5voto

miguel Points 1537

Notez que les pourcentages de gradientRadius fonctionnent dans Lollipop. Mais si vous devez prendre en charge les versions antérieures à Lollipop, j'ai développé la réponse de @marnaish en ajoutant des attributs XML. Mon gradientRadius est défini comme un pourcentage de la largeur de la vue parent :

public class RadialGradientView extends View {
    private final int endColor;
    private final int startColor;
    private final float gradientRadiusWidthPercent;
    private final float centerY;
    private final float centerX;
    private Paint paint;

    public RadialGradientView(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RadialGradientView, 0, 0);

        startColor = a.getColor(R.styleable.RadialGradientView_startColor, Color.RED);
        endColor = a.getColor(R.styleable.RadialGradientView_endColor, Color.BLACK);
        gradientRadiusWidthPercent = a.getFloat(R.styleable.RadialGradientView_gradientRadiusWidthPercent, 1);
        centerX = a.getFloat(R.styleable.RadialGradientView_centerX, .5f);
        centerY = a.getFloat(R.styleable.RadialGradientView_centerY, .5f);

        a.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        RadialGradient gradient = new RadialGradient(
                parentWidth*centerX,
                parentHeight*centerY,
                parentWidth*gradientRadiusWidthPercent,
                new int[] {startColor, endColor},
                null,
                android.graphics.Shader.TileMode.CLAMP);

        paint.setDither(true);
        paint.setShader(gradient);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
    }

}

Dans attrs.xml :

<declare-styleable name="RadialGradientView">
    <attr name="startColor" format="color|reference"/>
    <attr name="endColor" format="color|reference"/>
    <attr name="gradientRadiusWidthPercent" format="float"/>
    <attr name="centerX" format="float"/>
    <attr name="centerY" format="float"/>
</declare-styleable>

Malheureusement, il n'est pas possible de créer une table traçable XML à partir d'une classe personnalisée, ce qui signifie que vous ne pouvez pas la définir comme arrière-plan Android:background d'une vue. La solution de contournement consiste à utiliser un FrameLayout pour le superposer comme arrière-plan.

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="100dp">

    <com.RadialGradientView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:centerX=".3"
        app:centerY=".5"
        app:endColor="#0f0"
        app:startColor="#f00"
        app:gradientRadiusWidthPercent=".5"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="What's up world?"/>
</FrameLayout>

0voto

Josh Points 58

Vous pourriez créer une forme traçable au moment de l'exécution, en vous inspirant de cet article. https://stackoverflow.com/a/4943888/604504

De cette façon, vous pourriez calculer le pourcentage après avoir récupéré la taille de l'écran.

0voto

siiiiiix Points 89

Il est impossible de définir un rayon d'angle de forme exprimé en pourcentage dans un xml dessinable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X