设计用于裁剪ImageView的路径

Gio*_*rio 1 java android path shape

好吧,我需要裁剪特定形状的ImageView,我不能通过添加png来实现这一点,因为背景可以变化(例如模式).所以,我需要形状外的区域是透明的.

形状必须是这样的:

形状

我想用Path()来绘制这个形状并使用它来掩盖ImageView,但我完全不知道如何使用Path()绘制这样的复杂形状.

非常感谢.

kco*_*ock 5

所以我很无聊,这看起来很有趣,所以我把一个简单的Drawable扔在一起,你可以用来做这件事.您可以获得更好的动画并添加笔画等等,但这适用于您建议的基本情况,并允许您将箭头设置为指向任何角落,并且还可以缩放图像以适应边界可绘制的.这是结果:

例

你可以用它来:

BubbleDrawable bubbleDrawable = new BubbleDrawable(
        this, R.drawable.your_image, BubbleDrawable.Corner.TOP_RIGHT);
myImageView.setImageDrawable(bubbleDrawable);
Run Code Online (Sandbox Code Playgroud)

这是BubbleDrawable的代码:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;

import static android.graphics.Matrix.ScaleToFit.FILL;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Path.Direction.CW;
import static android.graphics.PixelFormat.TRANSPARENT;
import static android.graphics.Shader.TileMode.CLAMP;
import static test.com.testrotationanimation.BubbleDrawable.Corner.TOP_LEFT;

public final class BubbleDrawable extends Drawable {
    private final Matrix mMatrix = new Matrix();
    private final Paint mPaint = new Paint(ANTI_ALIAS_FLAG);
    private final Path mPath = new Path();
    private final RectF mSrcRect = new RectF();
    private final RectF mDstRect = new RectF();
    private final Shader mShader;

    private Corner mArrowCorner = TOP_LEFT;

    public BubbleDrawable(Bitmap bitmap, Corner arrowCorner) {
        // Initialize a BitmapShader with the image you wish to draw
        // (you can use other TileModes like REPEAT or MIRROR if you prefer)
        mShader = new BitmapShader(bitmap, CLAMP, CLAMP);
        mPaint.setShader(mShader);

        // Save the bounds of the bitmap as the src rectangle -- will
        // be used later to update the matrix when the bounds change
        // so that the image fits within the bounds of this drawable
        mSrcRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());

        // Set the corner in which the arrow will be drawn
        mArrowCorner = arrowCorner;
    }

    public BubbleDrawable(Context ctx, int drawableResource, Corner arrowCorner) {
        this(BitmapFactory.decodeResource(ctx.getResources(), drawableResource), arrowCorner);
    }

    public Corner getArrowCorner() {
        return mArrowCorner;
    }

    public void setArrowCorner(Corner corner) {
        mArrowCorner = corner;
        updatePath();
        invalidateSelf();
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        updateMatrix(bounds);
        updatePath();
    }

    private void updateMatrix(Rect bounds) {
        // Set the destination rectangle for the bitmap to be the
        // new drawable bounds
        mDstRect.set(bounds);

        // Scale the bitmap's rectangle to the bounds of this drawable
        mMatrix.setRectToRect(mSrcRect, mDstRect, FILL);

        // Update the shader's matrix (to draw the bitmap at the right size)
        mShader.setLocalMatrix(mMatrix);
    }

    private void updatePath() {
        final Rect bounds = getBounds();
        final float x = bounds.exactCenterX();
        final float y = bounds.exactCenterY();

        // Draw the initial circle (same for all corners)
        mPath.reset();
        mPath.addCircle(x, y, Math.min(x, y), CW);

        // Add the rectangle which intersects with the center,
        // based on the corner in which the arrow should draw
        switch (mArrowCorner) {
            case TOP_LEFT:
                mPath.addRect(bounds.left, bounds.top, x, y, CW);
                break;
            case TOP_RIGHT:
                mPath.addRect(x, bounds.top, bounds.right, y, CW);
                break;
            case BOTTOM_LEFT:
                mPath.addRect(bounds.left, y, x, bounds.bottom, CW);
                break;
            case BOTTOM_RIGHT:
                mPath.addRect(x, y, bounds.right, bounds.bottom, CW);
                break;
        }
    }

    @Override
    public void draw(Canvas canvas) {
        // Easy enough, just draw the path using the paint.
        // It already has the BitmapShader applied which
        // will do the work for you.
        canvas.drawPath(mPath, mPaint);
    }

    @Override
    public int getOpacity() {
        // Indicate that this Drawable has fully-transparent pixel values
        return TRANSPARENT;
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        // Yay, you can even support color filters for your drawable
        mPaint.setColorFilter(colorFilter);
    }

    @Override
    public void setAlpha(int i) {
        // You could do this by doing some canvas magic but I'm 
        // lazy and don't feel like it. Exercise for the reader. :)
        throw new UnsupportedOperationException("Not implemented.");
    }

    public enum Corner {
        TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我希望你将来再次感到无聊......:D,谢谢你,非常详细的解决方案! (4认同)