Android 九个补丁 - 只允许拉伸背景可绘制的特定区域

Android nine patch - allow only a specific area of a background drawable to stretch

如何创建具有三角形穿孔边界的 View

到目前为止,我一直在使用背景可绘制对象来实现这一点。这在 View 的尺寸固定时有效。现在我遇到了 Viewheight 不是常量的情况,所以我需要动态设置高度变量。我不能再使用固定高度的背景可绘制对象了。

这是原始背景图:

这就是最终 View 需要的样子:

看待同一问题的另一种方式是,我们能否让图像的中心在不扭曲边界的情况下拉伸?如果我们能做到这一点,我们就可以使用现有的可绘制对象作为背景。

如何实现?有没有其他人遇到过这个问题?该框架是否有现有的方法来处理这些 class 问题?

您可以生成九补丁 png 而不是使用普通图像。

为此使用 Simple Nine-patch Generator

诀窍是左边的黑线。这告诉 Android png 可以沿该区域垂直扩展。

请看这个例子:

将其保存为九个补丁,格式为 imagename.9.png

您可以使用 NinePatch 图像 作为该视图的可绘制对象。要了解如何创建 NinePatch 图像,请转到 Draw 9-patch

您可以在视图的背景中绘制一条之字形路径

Rect rectZigzag = new Rect();
private Path pathZigzag = new Path();
private Paint paintZigzag;
private void init(){
    this.paintZigzag = new Paint();
    this.paintZigzag.setColor(zigzagBackgroundColor);
    this.paintZigzag.setStyle(Style.FILL);
}


private void drawZigzag() {
    float left = rectZigzag.left;
    float right = rectZigzag.right;
    float top = rectZigzag.top;
    float bottom = rectZigzag.bottom;
    int width = (int) (right - left);

    pathZigzag.moveTo(right, bottom);
    pathZigzag.lineTo(right, top);
    pathZigzag.lineTo(left, top);
    pathZigzag.lineTo(left, bottom);

    int h = zigzagHeight;
    int seed = 2 * h;
    int count = width / seed;
    int diff = width - (seed * count);
    int sideDiff = diff / 2;


    float x = (float) (seed / 2);
    float upHeight = bottom - h;
    float downHeight = bottom;

    for (int i = 0; i < count; i++) {
        int startSeed = (i * seed) + sideDiff + (int) left;
        int endSeed = startSeed + seed;

        if (i == 0) {
            startSeed = (int) left + sideDiff;
        } else if (i == count - 1) {
            endSeed = endSeed + sideDiff;
        }

        this.pathZigzag.lineTo(startSeed + x, upHeight);
        this.pathZigzag.lineTo(endSeed, downHeight);
    }
}

refrence

9 补丁机制无法为我的用例做类似的事情,因为它需要在水平和垂直方向上定义一个可拉伸区域。 9 补丁仅在 ImageView 能够被限制为源可绘制对象的确切宽度时才有效,以避免任何水平拉伸。

如果需要允许视图水平拉伸,保持图像顶部和底部边界部分的纵横比,同时允许中间部分在两个方向上自由拉伸,9 patch 不会为此工作。我创建了这个布局来完成这个:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/backgroundImage"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/imageTop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="fitXY"
        android:adjustViewBounds="true"
        android:layout_weight="0"
        android:src="@drawable/image_top" />

    <ImageView
        android:id="@+id/imageMiddle"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"
        android:layout_weight="1"
        android:background="@drawable/image_middle" />

    <ImageView
        android:id="@+id/imageBottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="fitXY"
        android:adjustViewBounds="true"
        android:layout_weight="0"
        android:src="@drawable/image_bottom" />

</LinearLayout>

image_top.png

image_middle.png (请注意,如果不需要右侧的细微灰色渐变,则此图像可以缩小到 1 像素高。)

image_bottom.png

关键是在边界图像上有android:adjustViewBounds="true",而drawables用android:src指定。然后中间的图像用 android:background 指定可绘制对象并调整大小以用 android:layout_height="match_parent"android:layout_weight="1".

填充父布局的高度

android:scaleType="fitXY" 是必要的,以便在调整图像的视图边界以处理高分辨率显示器上对齐中任何潜在的微小像素差异后强制对图像进行最终缩放。它们都已调整大小以完全填充它们的边界。