Android nine patch - allow only a specific area of

2019-03-17 01:59发布

How does one go about creating a View that has boundaries with triangular perforations ?

enter image description here

I've been using background drawables to achieve this so far. That works when the dimensions of the View are fixed. Now I have a situation where the height of the View is not constant, so I need to have the height variable on the fly. I can't use a background drawable with a fixed height anymore.

Here is the original background drawable:

enter image description here

And this is what the final View needs to look like:

enter image description here

Another way of looking at the same problem is, can we allow the center of the image to stretch without distorting the boundaries ? If we could do this, we could use the existing drawable as a background.

How can this be achieved ? Has anyone else faced this problem before ? Does the framework have an existing way of dealing with this class of problems ?

4条回答
Explosion°爆炸
2楼-- · 2019-03-17 02:38

The 9 patch mechanism didn't work to do something similar for my use case, because it requires a stretchable region to be defined in both the horizontal and vertical directions. The 9 patch will only work if the ImageView is able to be constrained to the exact width of the source drawables, to avoid any horizontal stretching.

If the view needs to be allowed to stretch horizontally, maintaining the aspect ratio of the top and bottom boundary portions of the image, while the middle portion is allowed to stretch freely in both directions, a 9 patch won't work for this. I created this layout to accomplish this:

<?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 enter image description here

image_middle.png enter image description here (Note, this image could be shrunk to as little as 1 pixel high, if the subtle gray gradient on the right isn't necessary.)

image_bottom.png enter image description here

The key is having android:adjustViewBounds="true" on the boundary images, while the drawables are specified with android:src. Then the middle image specifies the drawable with android:background and resizes to fill the height of the parent layout with android:layout_height="match_parent" and android:layout_weight="1".

android:scaleType="fitXY" was necessary in addition in order to force a final scaling of the images after their view bounds are adjusted to handle any potential tiny pixel differences in alignment on hi-res displays. They are all resized to fill their bounds completely.

查看更多
叛逆
3楼-- · 2019-03-17 02:41

You can use a NinePatch image as drawable of that view. To learn how to create a NinePatch image, goto Draw 9-patch

查看更多
来,给爷笑一个
4楼-- · 2019-03-17 02:45

Instead of using a normal image, you can generate a nine-patch png.

Use Simple Nine-patch Generator for this.

The trick is the black line on the left side. That tells Android that the png is vertically expandable along this area.

Please see this example:

Nine Patch Example

Save it as a nine-patch, in the format imagename.9.png

查看更多
Bombasti
5楼-- · 2019-03-17 03:04

You can draw a zigzag path in background of your view

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

查看更多
登录 后发表回答