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.

Vikram
  • 51,313
  • 11
  • 93
  • 122
  • 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);` – mikepenz May 09 '15 at 17:47
  • @mikepenz 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_. – Vikram May 09 '15 at 17:56
  • 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();` – mikepenz May 09 '15 at 18:01
  • @mikepenz 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. – Vikram May 09 '15 at 18:15
  • 2
    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. – mikepenz May 09 '15 at 18:18
  • @mikepenz Could very well be the case. Hope someone can provide an explanation for this. – Vikram May 09 '15 at 18:33
  • This is a good question, I think. Hope someone can provide an explanation here. PS: @mikepenz are you the Mike Penz in my FB friends' list? – SilentKnight May 18 '15 at 03:10
  • @SilentKnight I don't know. i am this one: https://github.com/mikepenz/MaterialDrawer – mikepenz May 19 '15 at 05:09

2 Answers2

4

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

Abtin Gramian
  • 1,630
  • 14
  • 13
0
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;
}
General Grievance
  • 4,555
  • 31
  • 31
  • 45