ImageSpan在Android 5上无法正常工作

11

我有一个在Android 4.4.1上很好用的函数,在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;
  }

我是这样使用它的:

class MyButton extends Button {

    // ... snip ...

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

这里是上述提到的getDrawable()方法:

 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;
  }

我在调试时,所有的东西似乎都成功了,但是没有绘制任何图像。 有什么想法我可能做错了吗?


我创建了一个继承自android.widget.Button的类,尝试在运行KitKat的模拟器上使用您的prependImage(Drawable, String)方法,但是图像没有被绘制。 - Jared Rummler
好的,应该有一种方法可以使它在两个上绘制。我很乐意放弃这个并尝试其他事情。你确定将可绘制对象的边界设置为除0,0,0,0之外的其他值了吗? - i_am_jorf
@i_am_jorf 你可以使用 TextView 替代 Button。在所有的 Android 版本中,使用 TextView 看起来都很正常。 - Abhishek V
你好,您正在测试哪里?在搭载Android 5.1.1的Nexus 5上运行正常。 - Blackbelt
我正在三星S6(5.1)和S4(4.4)上进行测试。 - i_am_jorf
5个回答

23

默认情况下,在Material设计中,按钮会将文本显示为全大写。然而,AllCapsTransformationMethod用于大写处理的bug会导致Spannable数据被丢弃。

你可以通过在Button上指定android:textAllCaps="false"来覆盖默认的按钮样式并禁用全大写。

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

看一下这里


3
谷歌安卓系统真是让人崩溃...感谢你,伙计。 - Anton Shkurenko
你是上帝,谢谢你拯救了我的一天 :) - bulubuloa

4

您与Spannables相关的代码没问题。您可以通过为TextView设置文本来检查它。

问题出在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>

有两个解决方案。

第一个是只需使用TextView作为您的按钮,并将图像设置为其文本。

对于另一种(可能更正确的)方式,您需要以以下方式扩展按钮样式(Widget.Material.Button):

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

然后在你的布局中:

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

在你完成后,你应该可以在按钮中看到这些图片。

不要忘记,对于版本低于5.0的Android,你也应该创建BtnStyle,但在其他资源目录中(res/values-v14/style.xml)。


这似乎是最合理的解决方案。谢谢。 - i_am_jorf
我看到这篇帖子,就像是“让我们去吃点赏金”,但它已经解决了。 - Elltz

1

需要注意的是,可绘制矢量图无法使用,您必须要么有一个png或jpeg格式的可绘制对象,要么将位图传递给ImageSpan。


0

试一下这个

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      getResources().getDrawable(R.drawable.your_drawable, getTheme());
            } else {
                getResources().
                        getDrawable(R.drawable.your_drawable);
            }

使用带有主题参数的新版本没有任何效果。 - i_am_jorf

0
也许您需要检查Drawable对象的内容,您使用getDrawable()方法获取Drawable对象,但API定义似乎与您的调用参数不匹配。
对于Android 5.0+:
getDrawable(int id)方法已在API级别22中弃用,请改用getDrawable(int, Theme)方法。
getDrawable(int id, Resources.Theme theme)方法返回与特定资源ID相关联并针对指定主题进行样式化的drawable对象。
第二个参数看起来像是一个主题(Theme),而不是颜色。对吗?

啊,抱歉。在 MyButton 类中我有一个叫做 getDrawable(int id, int color) 的私有方法,它封装了对 getContext().getResources().getDrawable(int id) 方法的调用,并且还会调用 drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);。这个方法返回一个看起来很合理的 drawable 画图对象。 - i_am_jorf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接