web-dev-qa-db-fra.com

Comment utiliser RippleDrawable par programmation dans du code (pas xml) avec Android 5.0 Lollipop?

J'ai le code suivant pour mon ondulation:

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:color="?android:colorControlHighlight">
    <item Android:id="@+id/rip">

        <shape Android:shape="oval">
            <solid Android:color="?android:colorAccent"/>
        </shape>
    </item>
</ripple>

Maintenant, je veux donner à l'utilisateur la possibilité de choisir ses propres couleurs, je dois donc créer l'ondulation par programme.
J'ai trouvé ceci et je pense que c'est la bonne façon de le faire, mais je ne sais pas comment gérer cela.

L'ondulation sera utilisée ici:

<ImageButton
    Android:id="@+id/add_button"
    Android:layout_width="@dimen/diameter"
    Android:layout_height="@dimen/diameter"
    Android:layout_gravity="end|bottom"
    Android:layout_marginBottom="@dimen/add_button_margin"
    Android:layout_marginEnd="@dimen/add_button_margin"
    Android:layout_alignParentBottom="true"
    Android:layout_alignParentEnd="true"
    Android:src="@drawable/ic_action_add_person"
    Android:tint="@Android:color/white"
    Android:background="@drawable/oval_ripple"
    Android:elevation="@dimen/elevation_low"
    Android:stateListAnimator="@anim/button_elevation"
    Android:contentDescription="Neuer Spieler" />

Je dois définir l'arrière-plan sur un RippleDrawable comme ceci:

addButton.setBackground(ripple);
28
ich5003

C'est ainsi que j'ai pu y parvenir.

Notez qu'il s'agit d'Api 21+ uniquement, vous devrez donc revenir à un Drawable normal si vous prenez en charge les versions inférieures.

public static RippleDrawable getPressedColorRippleDrawable(int normalColor, int pressedColor)
{
    return new RippleDrawable(getPressedColorSelector(normalColor, pressedColor), getColorDrawableFromColor(normalColor), null);
}

public static ColorStateList getPressedColorSelector(int normalColor, int pressedColor)
{
    return new ColorStateList(
        new int[][]
            {
                new int[]{Android.R.attr.state_pressed},
                new int[]{Android.R.attr.state_focused},
                new int[]{Android.R.attr.state_activated},
                new int[]{}
            },
        new int[]
            {
                pressedColor,
                pressedColor,
                pressedColor,
                normalColor
            }
    );
}

public static ColorDrawable getColorDrawableFromColor(int color)
{
    return new ColorDrawable(color);
}

Edit: J'ai bricolé avec cela un peu plus et découvert que ColorStateList n'a pas besoin d'être presque aussi complexe que la solution ci-dessus. Je l'ai simplifié pour l'extrait ci-dessous. (Tout le reste dans le bloc de code ci-dessus est le même. Je n'ai changé que la création de ColorStateList.) Je laisserai le bloc ci-dessus comme original, au cas où cette méthode ne fonctionnerait pas pour quelqu'un.

new ColorStateList(
    new int[][]
        {
            new int[]{}
        },
    new int[]
        {
            pressedColor
        }
);
52
kdenney
public static Drawable getAdaptiveRippleDrawable(
    int normalColor, int pressedColor) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
        return new RippleDrawable(ColorStateList.valueOf(pressedColor),
                null, getRippleMask(normalColor));
    } else {
        return getStateListDrawable(normalColor, pressedColor);
    }
}

private static Drawable getRippleMask(int color) {
    float[] outerRadii = new float[8];
    // 3 is radius of final ripple, 
    // instead of 3 you can give required final radius
    Arrays.fill(outerRadii, 3);

    RoundRectShape r = new RoundRectShape(outerRadii, null, null);
    ShapeDrawable shapeDrawable = new ShapeDrawable(r);
    shapeDrawable.getPaint().setColor(color);
    return shapeDrawable;
}

public static StateListDrawable getStateListDrawable(
    int normalColor, int pressedColor) {
    StateListDrawable states = new StateListDrawable();
    states.addState(new int[]{Android.R.attr.state_pressed}, 
        new ColorDrawable(pressedColor));
    states.addState(new int[]{Android.R.attr.state_focused}, 
        new ColorDrawable(pressedColor));
    states.addState(new int[]{Android.R.attr.state_activated}, 
        new ColorDrawable(pressedColor));
    states.addState(new int[]{}, 
        new ColorDrawable(normalColor));
    return states;
}

Vous pouvez obtenir le dessin et appliquer à n'importe quelle vue en utilisant view.setDrawable.
Pour les appareils Lollipop +, vous obtiendrez une ondulation sinon cela changera la couleur de la vue.

21
Ashok Varma

Fondamentalement, vous devez créer un nouvel objet RippleDrawable. Pour les appareils pré-Lollipop, vous voulez un StateListDrawable (comme d'autres l'ont déjà suggéré). J'ai écrit un Gist quelque peu ingénieux avec un tas de méthodes utiles liées aux Drawables et à la coloration: https://Gist.github.com/milosmns/6566ca9e3b756d922aa5

Vous voudrez probablement utiliser #getBackgroundDrawable() à partir de ce singleton.

2
milosmns