我应该如何在Android中为图像提供圆角?

iam*_*koa 38 java android image

我想改变我加载的图像有圆角.

您知道的任何提示,教程,最佳实践?

Ral*_*eon 45

对于更受控制的方法,使用绘制的porter-duff Xfer模式绘制圆角矩形并将其遮罩到图像上.

首先设置Xfer绘图和圆角位图:

Bitmap myCoolBitmap = ... ; // <-- Your bitmap you want rounded    
int w = myCoolBitmap.getWidth(), h = myCoolBitmap.getHeight();

// We have to make sure our rounded corners have an alpha channel in most cases
Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(rounder);    

// We're going to apply this paint eventually using a porter-duff xfer mode.
// This will allow us to only overwrite certain pixels. RED is arbitrary. This
// could be any color that was fully opaque (alpha = 255)
Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xferPaint.setColor(Color.RED);

// We're just reusing xferPaint to paint a normal looking rounded box, the 20.f
// is the amount we're rounding by.
canvas.drawRoundRect(new RectF(0,0,w,h), 20.0f, 20.0f, xferPaint);     

// Now we apply the 'magic sauce' to the paint  
xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
Run Code Online (Sandbox Code Playgroud)

现在将此位图应用于图像的顶部:

Bitmap result = Bitmap.createBitmap(myCoolBitmap.getWidth(), myCoolBitmap.getHeight() ,Bitmap.Config.ARGB_8888);
Canvas resultCanvas = new Canvas(result)
resultCanvas.drawBitmap(myCoolBitmap, 0, 0, null);
resultCanvas.drawBitmap(rounder, 0, 0, xferPaint);
Run Code Online (Sandbox Code Playgroud)

带圆角的位图现在位于结果中.

  • 这种方法的问题是你必须经过一个中间位图。如果您需要快速和/或经常绘制许多不同的圆角位图,这可能是一个问题。一种更简单的方法是使用在 Paint 上设置的 BitmapShader 简单地调用 drawRect()。写起来也更容易:) (2认同)

Jer*_*rry 29

为什么不使用clipPath?

protected void onDraw(Canvas canvas) {
    Path clipPath = new Path();
    float radius = 10.0f;
    float padding = radius / 2;
    int w = this.getWidth();
    int h = this.getHeight();
    clipPath.addRoundRect(new RectF(padding, padding, w - padding, h - padding), radius, radius, Path.Direction.CW);
    canvas.clipPath(clipPath);
    super.onDraw(canvas);
}
Run Code Online (Sandbox Code Playgroud)

  • 某些3.0及更高版本的设备使用的硬件加速模式不支持clipPath.如果您在启用硬件加速的情况下运行此代码,则会出现异常(并且您确实希望为任何支持该设置的手机启用该设置) (22认同)
  • 这种方法的问题是即使在软件中,clipPath也不支持抗锯齿. (9认同)
  • 注意,在尝试这个之后我发现:1 - 你首先剪辑画布然后绘制位图2 - 它不比使用位图蒙版和xfer模式叠加3快 - 一个不能反别名clipPath,而一个可以消除别名为xfer模式叠加绘制遮罩的paint. (2认同)

Dhe*_*.S. 17

Romain Guy自己在他的博客中写道:

为了生成圆角图像,我简单地编写了一个自定义Drawable,它使用Canvas.drawRoundRect()绘制一个圆角矩形.诀窍是使用带有BitmapShader的Paint用纹理而不是简单的颜色填充圆角矩形.这是代码的样子:

BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);

RectF rect = new RectF(0.0f, 0.0f, width, height);

// rect contains the bounds of the shape
// radius is the radius in pixels of the rounded corners
// paint contains the shader that will texture the shape
canvas.drawRoundRect(rect, radius, radius, paint);
Run Code Online (Sandbox Code Playgroud)

通过将BitmapShader与RadialGradient相结合,示例应用程序更进一步,并伪装了晕影效果.


Lea*_* ES 7

这是我发现用ImageView做的一种方式.我尝试了其他方法,包括这里的答案和类似的问题,但我发现它们对我来说效果不好,因为我需要将角应用于图像视图而不是直接应用于位图.如果您正在缩放/裁剪/平移该位图,则直接应用于位图将不起作用,因为角也将缩放/裁剪/平移.

public class RoundedCornersImageView extends ImageView {
    private final Paint restorePaint = new Paint();
    private final Paint maskXferPaint = new Paint();
    private final Paint canvasPaint = new Paint();

    private final Rect bounds = new Rect();
    private final RectF boundsf = new RectF();

    public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public RoundedCornersImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundedCornersImageView(Context context) {
        super(context);
        init();
    }

    private void init() {
        canvasPaint.setAntiAlias(true);
        canvasPaint.setColor(Color.argb(255, 255, 255, 255));
        restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
        maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.getClipBounds(bounds);
        boundsf.set(bounds);

        canvas.saveLayer(boundsf, restorePaint, Canvas.ALL_SAVE_FLAG);
        super.onDraw(canvas);

        canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawRoundRect(boundsf, 75, 75, canvasPaint);

        canvas.restore();
        canvas.restore();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是使用最终图层合成的硬件层的替代方案:

public class RoundedCornersImageView extends ImageView {
    private final Paint restorePaint = new Paint();
    private final Paint maskXferPaint = new Paint();
    private final Paint canvasPaint = new Paint();

    private final Rect bounds = new Rect();
    private final RectF boundsf = new RectF();

    public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public RoundedCornersImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundedCornersImageView(Context context) {
        super(context);
        init();
    }

    private void init() {
        canvasPaint.setAntiAlias(true);
        canvasPaint.setColor(Color.argb(255, 255, 255, 255));
        restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
        maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));

        setLayerType(View.LAYER_TYPE_HARDWARE, restorePaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.getClipBounds(bounds);
        boundsf.set(bounds);

        super.onDraw(canvas);

        canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawRoundRect(boundsf, 75, 75, canvasPaint);

        canvas.restore();
    }
}
Run Code Online (Sandbox Code Playgroud)

起初我无法使用这种方法,因为我的角落变黑了; 我后来才意识到在阅读这个问题后问题是什么:Android如何在ImageView上应用蒙版?.事实证明,修改画布中的alpha实际上是直接在屏幕上"刮掉",然后向下面的黑色窗口打孔.这就是为什么需要两个层的原因:一个用于应用蒙版,另一个用于将合成图像应用于屏幕.


Nav*_*vin 5

如何创建一个只有圆角并具有透明体的NinePatchDrawable图像.使用适当重新调整大小的NinePatchDrawable版本覆盖您的图像.