ImageSpan not working on Android 5
Asked Answered
O

5

11

I have this function that works fine on Android 4.4.1, but breaks on 5.0+.

  public static SpannableStringBuilder prependImage(Drawable drawable, String text) {
    SpannableStringBuilder builder = new SpannableStringBuilder("  " + text);
    builder.setSpan(new ImageSpan(drawable), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    return builder;
  }

And I use it like this:

class MyButton extends Button {

    // ... snip ...

    setText(
        prependImage(
            getDrawable(imageResource, color),                     
            getContext().getString(stringResource)),
        BufferType.SPANNABLE);

Here is the getDrawable() method referenced above:

 private Drawable getDrawable(int resource, int color) {
    final Resources resources = getContext().getResources();
    Drawable drawable = resources.getDrawable(resource);
    if (drawable != null) {
      drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
      drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
    }
    return drawable;
  }

When I debug, everything seems to succeed, but no image is drawn. Any ideas what I might be doing wrong?

Oxford answered 27/8, 2015 at 19:8 Comment(5)
I created a class that extends android.widget.Button, tried using your prependImage(Drawable, String) method on the emulator running KitKat and the image was not drawn.Eatage
Well, there should be a way to make it draw on both. I'm perfectly happy to throw this away and do something else. Did you make sure you set the bounds of the drawable to be something other than 0,0,0,0?Oxford
@Oxford You could use TextView instead of Button. It seems to be working fine with TextView in all the android versions.Lugansk
on a Nexus 5 with Android 5.1.1 is working. Where are you testing it ?Dual
I am testing on a Samsung S6 (5.1), and S4 (4.4).Oxford
H
4

Your code related to working with Spannables is ok. You can check it by setting text for TextView.

The problem is in material design of button on Android 5.0.

<style name="Widget.Material.Button">
    <item name="background">@drawable/btn_default_material</item>
    <item name="textAppearance">?attr/textAppearanceButton</item>
    <item name="minHeight">48dip</item>
    <item name="minWidth">88dip</item>
    <item name="stateListAnimator">@anim/button_state_list_anim_material</item>
    <item name="focusable">true</item>
    <item name="clickable">true</item>
    <item name="gravity">center_vertical|center_horizontal</item>
</style>

There are two solution.

The first one is just use TextView as your button and setText with image to it.

For another (and may be more correct) you need to extend button style (Widget.Material.Button) in next way:

<style name="BtnStyle" parent="android:Widget.Material.Button">
    <item name="android:textAppearance">@null</item>
</style>

Then in your layout:

<Button
    android:id="@+id/test2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Test"
    style="@style/BtnStyle"/>

After you'll do it you should see the images in the button.

Don't forget for Android version that is lower than 5.0 you should create BtnStyle too, but in other resource directory (res/values-v14/style.xml).

Hebe answered 30/9, 2015 at 7:42 Comment(2)
This seems like the most rational solution. Thanks.Oxford
i saw this post & i was like "lets go eat up some bounty" but its already solvedSlighting
M
23

By default, in Material buttons are styled to show text in all-caps. However, there is a bug in the AllCapsTransformationMethod used for capitalization that causes it to discard Spannable data.

You can override the default button styling and disable all-caps by specifying android:textAllCaps="false" on your Button.

<Button
    ...
    android:textAllCaps="false" />

have a look here

Mannerheim answered 30/9, 2015 at 13:19 Comment(1)
you are god, tks for save my day :)Deserved
H
4

Your code related to working with Spannables is ok. You can check it by setting text for TextView.

The problem is in material design of button on Android 5.0.

<style name="Widget.Material.Button">
    <item name="background">@drawable/btn_default_material</item>
    <item name="textAppearance">?attr/textAppearanceButton</item>
    <item name="minHeight">48dip</item>
    <item name="minWidth">88dip</item>
    <item name="stateListAnimator">@anim/button_state_list_anim_material</item>
    <item name="focusable">true</item>
    <item name="clickable">true</item>
    <item name="gravity">center_vertical|center_horizontal</item>
</style>

There are two solution.

The first one is just use TextView as your button and setText with image to it.

For another (and may be more correct) you need to extend button style (Widget.Material.Button) in next way:

<style name="BtnStyle" parent="android:Widget.Material.Button">
    <item name="android:textAppearance">@null</item>
</style>

Then in your layout:

<Button
    android:id="@+id/test2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Test"
    style="@style/BtnStyle"/>

After you'll do it you should see the images in the button.

Don't forget for Android version that is lower than 5.0 you should create BtnStyle too, but in other resource directory (res/values-v14/style.xml).

Hebe answered 30/9, 2015 at 7:42 Comment(2)
This seems like the most rational solution. Thanks.Oxford
i saw this post & i was like "lets go eat up some bounty" but its already solvedSlighting
L
1

One thing to note, drawable vectors won't work, you must either have a drawable which is a png or jpeg or pass to ImageSpan bitmap instead

Linden answered 10/8, 2020 at 10:26 Comment(0)
A
0

Maybe you need to check the content of that Drawable object, you use the getDrawable() to get the Drawable object, but the API definition seems not match your calling parameters.

For Android 5.0+

Drawable getDrawable(int id) This method was deprecated in API level 22. Use getDrawable(int, Theme) instead.

Drawable getDrawable(int id, Resources.Theme theme) Return a drawable object associated with a particular resource ID and styled for the specified theme.

The second parameter looks like to be a Theme, not a color. right ?

Aorangi answered 30/9, 2015 at 1:46 Comment(1)
Ah, sorry. I have a private method in MyButton called getDrawable(int id, int color) that wraps the call to getContext().getResources().getDrawable(int id) and also calls drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);. This returns, what looks like, a perfectly reasonable drawable.Oxford
J
0

try this

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      getResources().getDrawable(R.drawable.your_drawable, getTheme());
            } else {
                getResources().
                        getDrawable(R.drawable.your_drawable);
            }
Jowett answered 30/9, 2015 at 6:54 Comment(1)
Using the new version with theme parameter has no effect.Oxford

© 2022 - 2024 — McMap. All rights reserved.