Android - 可绘制重复形状以创建图案

Android - Drawable repeat shape to create pattern

我需要创建一个图案来设置为某些 View 的背景。我希望图案看起来像这样:

我不想将任何图像导入可绘制对象,而是想创建自己的形状、图层列表,最终目标是将图案作为背景。

是否可以在不导入任何外部图像的情况下实现这一点?

您可以通过创建自定义 View 并覆盖 onDraw().

来获得基于可绘制形状的重复图块的图案

让我们首先将图块创建为由形状可绘制对象组成的图层列表,在本例中为黑白交替的方块:

my_background.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
    <layer-list>
        <item >
            <shape >
                <solid android:color="#ffffff"/>
                <size
                    android:height="8dp"
                    android:width="8dp"
                    />
            </shape>
        </item>
        <item android:left="4dp" android:top="4dp" android:bottom="0dp" android:right="0dp" >
            <shape >
                <solid android:color="#ff000000"/>
                <size
                    android:height="4dp"
                    android:width="4dp"
                    />

            </shape>
        </item>
        <item android:left="0dp" android:top="0dp" android:bottom="4dp" android:right="4dp">
            <shape>
                <solid android:color="#ff000000"/>
                <size
                    android:height="4dp"
                    android:width="4dp"
                    />
            </shape>
        </item>
    </layer-list>
</item>

您需要一种方法 drawableToBitmap() 将图块转换为像 here 这样的位图。

覆盖 onDraw():

@Override
protected void onDraw(Canvas canvas)
{
    super.onDraw(canvas);
    Drawable d = getResources().getDrawable(R.drawable.my_background);
    if (d != null)
    {
        Bitmap b = drawableToBitmap(d);
        BitmapDrawable bm = new BitmapDrawable(getResources(), b);
        bm.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

        bm.setBounds(canvas.getClipBounds());
        bm.draw(canvas);
    }
}

根据 View 的类型,您可能需要采取额外的步骤。

  • 对于扩展某种 Layout 的自定义 View,将 android:background 属性设置为任何颜色以触发对 onDraw()[=66= 的调用]
  • 对于许多 View 来说,将您的自定义 View 置于另一个 View 之下可能更容易实施,同时性能更好(例如,作为两个 children in a RelativeLayout) 并使大小匹配。
  • 如果您想从 ImageView 扩展,您需要在背景图案之上绘制前景可绘制对象。这种情况下,可以修改onDraw()如下:

onDraw() 保留前景可绘制对象:

@Override
protected void onDraw(Canvas canvas)
{
    super.onDraw(canvas);

    // preserve foreground drawable if there is one:
    Drawable fd = getDrawable();

    Drawable d = getResources().getDrawable(R.drawable.my_background);
    if (d != null)
    {
        Bitmap b = drawableToBitmap(d);
        BitmapDrawable bm = new BitmapDrawable(getResources(), b);
        bm.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

        bm.setBounds(canvas.getClipBounds());
        bm.draw(canvas);
    }

    if (fd == null)
        return;

    // set bounds as needed
    fd.setBounds(0, 0, 100, 100);
    fd.draw(canvas);
}

编辑

如上所述,在某些情况下(例如 TextViewProgressBar)您可能需要使用解决方法:

  • 使您的 View 背景透明。
  • 使用图案作为背景创建自定义布局。
  • 在自定义布局中包裹 View(将布局宽度和高度设置为 wrap_content)。