4

我正在做一个简单的项目,我想尽可能避免使用 PNG 图像。我需要一个“+”(添加)按钮,我使用 ShapeDrawable 和给定的代码创建了它。

res/drawable/plus_icon_drawable.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="line">
            <stroke android:color="#000"
                android:width="3dp"/>
        </shape>
    </item>
    <item>
        <rotate
            android:fromDegrees="90"
            android:toDegrees="90">
            <shape android:shape="line">
                <stroke android:color="#000"
                    android:width="3dp"/>
            </shape>
        </rotate>
    </item>
</layer-list>

当我将其添加为 Button 或 ImageButton 的背景时,此代码可以正常工作,但是当我将其添加为 ActionBar 项目的图标时,该项目不会显示。

当我将 PNG 图像设置为图标时,它工作正常。ShapeDrawables 是否有任何限制阻止它在 ActionBar 上呈现?

这是我的 ActionBar 代码

res/menu/action_my_actions.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/action_some_id"
        android:icon="@drawable/plus_icon_drawable"
        android:title="My Action"
        android:showAsAction="always"/>
</menu>

更新(2014 年 7 月 8 日):使用 Native 和 AppCompat 测试。实际上该项目在那里存在,但 ShapeDrawable 图像没有被渲染。操作项响应点击。

我在这里想念什么?

4

1 回答 1

3

ShapeDrawables 是否有任何限制阻止它在 ActionBar 上呈现?

没有那样的事。事情就是这样。这就是您看到此内容的原因:

Layer/ShapeDrawables没有默认大小。换句话说,aShapeDrawable的宽度和高度为零是完全可以的。stroke-width 参数也没有规定任何内容。

当我将其添加为 Button 或 ImageButton 的背景时,此代码可以正常工作,但是当我将其添加为 ActionBar 项目的图标时,该项目不会显示。

是的当然。ImageButtons/Buttons有填充/最小宽度/最小高度的概念。这些让ShapeDrawable他们有一些呼吸的空间。例如,样式为 的 ButtonWidget.Holo.Button将具有minWidthandminHeight设置:

<item name="android:minHeight">48dip</item>
<item name="android:minWidth">64dip</item>

这里的有效测试是:

定义ImageView如下:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/add" />

</RelativeLayout>

上面的ImageView定义中没有尺寸指南 - 我们使用的是wrap_content. 什么都不会显示。另一方面,如果您使用 png 可绘制对象,它本身会定义大小。在上面的示例中,使用显式大小(例如 50dp)将使ShapeDrawable visible.

这是ActionMenuItemView设置drawable的方式:

public void setIcon(Drawable icon) {
    mIcon = icon;
    if (icon != null) {

        // Zero in case you don't define the <size /> 
        int width = icon.getIntrinsicWidth();
        int height = icon.getIntrinsicHeight();
        if (width > mMaxIconSize) {
            final float scale = (float) mMaxIconSize / width;
            width = mMaxIconSize;
            height *= scale;
        }
        if (height > mMaxIconSize) {
            final float scale = (float) mMaxIconSize / height;
            height = mMaxIconSize;
            width *= scale;
        }
        icon.setBounds(0, 0, width, height);
    }
    setCompoundDrawables(icon, null, null, null);

    updateTextButtonVisibility();
}

方法片段ShapeDrawable#inflate(...)

 setIntrinsicWidth((int)
            a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f));
 setIntrinsicHeight((int)
            a.getDimension(com.android.internal.R.styleable.ShapeDrawable_height, 0f));

如果没有定义,则固有宽度ShapeDrawable_widthShapeDrawable_height高度将设置为零。这意味着,语句icon.setBounds(0, 0, width, height);(来自 setIcon(Drawable) 方法)实际上是 => icon.setBounds(0, 0, 0, 0);

所以,看来我们确实在处理ShapeDrawables没有尺寸信息的问题。

一个可能的修复:

<shape android:shape="line">
    <size android:width="?android:attr/actionBarSize"
          android:height="?android:attr/actionBarSize"/>
    <stroke android:color="#000"
            android:width="3dp"/>
</shape>

但这不起作用——由于某种原因?android:attr/actionBarSize,它不被视为一个维度。这很奇怪,因为在布局的情况下?android:attr/actionBarSize提供给它时​​可以正常工作。android:layout_width

解决方法是定义一个新维度,比如说actionBarSizeDp并设置它:

res/values/dimens.xml

<dimen name="actionBarSizeDp">48dp</dimen>

res/values-land/dimens.xml

<dimen name="actionBarSizeDp">40dp</dimen>

这些值是 android 自己的 res/values-XX/dimens.xml 中定义的默认操作栏大小值。

最后,actionBarSizeDp使用plus_icon_drawable.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="line">
            <size android:width="@dimen/actionBarSizeDp"
                  android:height="@dimen/actionBarSizeDp"/>
            <stroke android:color="#000"
                    android:width="3dp"/>
        </shape>
    </item>
    <item>
        <rotate
            android:fromDegrees="90"
            android:toDegrees="90">
            <size android:width="@dimen/actionBarSizeDp"
                  android:height="@dimen/actionBarSizeDp"/>
            <shape android:shape="line">
                <stroke android:color="#000"
                        android:width="3dp"/>
            </shape>
        </rotate>
    </item>
</layer-list>

事实上,定义size其中之一LayerDrawables就足够了。其他(S)将相应地绘制。

于 2014-08-04T20:11:55.903 回答