RippleDrawable created programmatically looks different from its xml counterpart
Asked Answered
B

2

14

I have been trying to trace this issue for a while now. I think I did find an explanation some time ago. Unfortunately, its lost in code-comments somewhere.

I am trying to create a Material Borderless-Button in Java. To start with, here's what the button looks like in the framework:

Button bg (button_borderless_material.xml):

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

The drawable being used as mask (btn_default_mtrl_shape.xml):

<?xml version="1.0" encoding="utf-8"?>
<!-- Used as the canonical button shape. -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
       android:insetLeft="@dimen/button_inset_horizontal_material"
       android:insetTop="@dimen/button_inset_vertical_material"
       android:insetRight="@dimen/button_inset_horizontal_material"
       android:insetBottom="@dimen/button_inset_vertical_material">
    <shape android:shape="rectangle"
           android:tint="?attr/colorButtonNormal">
        <corners android:radius="@dimen/control_corner_material" />
        <solid android:color="@color/white" />
        <padding android:left="@dimen/button_padding_horizontal_material"
                 android:top="@dimen/button_padding_vertical_material"
                 android:right="@dimen/button_padding_horizontal_material"
                 android:bottom="@dimen/button_padding_vertical_material" />
    </shape>
</inset>

Java equivalent of the inset-drawable (btn_default_mtrl_shape.xml):

Drawable createButtonShape(Context context, int color) {
    Resource res = context.getResources();
    int radius = res
            .getDimensionPixelSize(R.dimen.control_corner_material);
    int paddingH = res
            .getDimensionPixelSize(R.dimen.button_padding_horizontal_material);
    int paddingV = res
            .getDimensionPixelSize(R.dimen.button_padding_vertical_material);
    int insetH = context.getResources()
            .getDimensionPixelSize(R.dimen.button_inset_horizontal_material);
    int insetV = res
            .getDimensionPixelSize(R.dimen.button_inset_vertical_material);

    float[] outerRadii = new float[8];
    Arrays.fill(outerRadii, radius);

    RoundRectShape r = new RoundRectShape(outerRadii, null, null);

    ShapeDrawable shapeDrawable = new ShapeDrawable(r);
    shapeDrawable.getPaint().setColor(color);
    shapeDrawable.setPadding(paddingH, paddingV, paddingH, paddingV);

    return new InsetDrawable(shapeDrawable,
            insetH, insetV, insetH, insetV);
}

The color argument is obtained from theme's attr/colorButtonNormal - the same color used with android:tint in xml definition.

The RippleDrawable created programmatically:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
Drawable createButtonRippleBg(Context context,
                                             int colorButtonNormal,
                                             int colorControlHighlight) {
    return new RippleDrawable(ColorStateList.valueOf(colorControlHighlight),
                    null, createButtonShape(context, colorButtonNormal));
}

I am aware that even though the mask-color/shape is not rendered visually, its alpha does affect the RippleDrawable. This is not an issue here - all colors being used for the mask have full-blown alpha.

I have also confirmed that the colors being read from attributes - colorControlHighlight & colorButtonNormal - are correct for the theme at play.

Yet, the result is:

Xml rendition:

enter image description here

In Java:

enter image description here

Interesting bit is that this happens on API 21. On API 22, both approaches produce identical results.

The question:

I am certain that this is a bug on API 21. If someone can track this down, we can probably find a multiplier for the alpha/color value to offset this visual difference.

In addition to general good-will, I also promise a bounty as I have already spent quite some time on this.

Brachyuran answered 9/5, 2015 at 17:32 Comment(8)
The only difference i see is that via xml you set the color as tint android:tint="?attr/colorButtonNormal" and via code you set it as color shapeDrawable.getPaint().setColor(color);Potassium
@Potassium Yea, the color argument is actually obtained from theme's colorButtonNormal. I mentioned this above: The color argument is obtained from theme's attr/colorButtonNormal - the same color used with android:tint in xml definition.Brachyuran
no this is not the thing i mean. You set it as color shapeDrawable.getPaint().setColor(color) in the xml as tint. why not set it as tint too via code? shapeDrawable.setTint();Potassium
@Potassium Oh, I see what you mean. I did try that before - the visual difference remained. I also tried applying a ColorFilter using PorterDuffColorFilter with Mode.MULTIPLY. The output was not as expected. Moreover, the problem is not present on API 22 which leads me to believe that the xml rendition on API 21 has a bug.Brachyuran
oh i see. I can't prove it but as of the screenshots it looks like the xml display on API 21 just draws the shape twice. so it overlaps the same background a second time.Potassium
@Potassium Could very well be the case. Hope someone can provide an explanation for this.Brachyuran
This is a good question, I think. Hope someone can provide an explanation here. PS: @Potassium are you the Mike Penz in my FB friends' list?Orthoptic
@Orthoptic I don't know. i am this one: github.com/mikepenz/MaterialDrawerPotassium
B
4

Try this alternate constructor new RippleDrawable(ColorStateList.valueOf(colorRipple), backgroundDrawable, null);

Benedikta answered 16/10, 2016 at 4:25 Comment(0)
E
-1
body {
    font-family: 'Lobster', cursive;
    background-color: #000;
    color: #fff;
    min-height: 100vh;
    display: grid;
    place-items: center;
}

$duration: 4s;

.rotate {
    color: aquamarine;    
    position: relative; filter: blur (2px) contrast (4);    
    font-size: 118px;
}
Eringo answered 7/5, 2023 at 7:18 Comment(2)
/help/formattingTurmoil
What is this css supposed to do? Where does it go?Alienage

© 2022 - 2024 — McMap. All rights reserved.