在Android中,ImageView默认是一个矩形。如何使它成为一个圆角矩形(剪辑我的位图的所有4个角为圆角矩形)在ImageView?


请注意,从2021年起,只需使用ShapeableImageView


当前回答

非常感谢第一个回答。下面是修改后的版本,将矩形图像转换为正方形(和圆形),填充颜色作为参数传递。

public static Bitmap getRoundedBitmap(Bitmap bitmap, int pixels, int color) {

    Bitmap inpBitmap = bitmap;
    int width = 0;
    int height = 0;
    width = inpBitmap.getWidth();
    height = inpBitmap.getHeight();

    if (width <= height) {
        height = width;
    } else {
        width = height;
    }

    Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, width, height);
    final RectF rectF = new RectF(rect);
    final float roundPx = pixels;

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(inpBitmap, rect, rect, paint);

    return output;
}

其他回答

通过使用下面的代码,您可以改变顶部角半径

val image = findViewById<ImageView>(R.id.image)
val curveRadius = 20F

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

    image.outlineProvider = object : ViewOutlineProvider() {

        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun getOutline(view: View?, outline: Outline?) {
            outline?.setRoundRect(0, 0, view!!.width, (view.height+curveRadius).toInt(), curveRadius)
        }
    }

    image.clipToOutline = true

}

最近,还有另一种方法——使用Glide的生成API。它需要一些初始的工作,但它给了你Glide所有的力量,以及做任何事情的灵活性,因为你重写了实际的代码,所以我认为从长远来看,这是一个很好的解决方案。另外,使用非常简单和整洁。

首先,设置Glide版本4+:

implementation 'com.github.bumptech.glide:glide:4.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'

然后创建Glid的app模块类来触发注释处理:

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}

然后创建实际工作的Glide扩展。你可以自定义它来做任何你想做的事情:

@GlideExtension
public class MyGlideExtension {

    private MyGlideExtension() {}

    @NonNull
    @GlideOption
    public static RequestOptions roundedCorners(RequestOptions options, @NonNull Context context, int cornerRadius) {
        int px = Math.round(cornerRadius * (context.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
        return options.transforms(new RoundedCorners(px));
    }
}

添加这些文件之后,构建您的项目。

然后像这样在你的代码中使用它:

GlideApp.with(this)
        .load(imageUrl)
        .roundedCorners(getApplicationContext(), 5)
        .into(imageView);

如果你不希望边框影响图像,使用这个类。不幸的是,我没有找到任何方法来绘制画布上的透明区域来到onDraw()。这里创建了一个新的位图它是画在一个真实的画布上的。

如果您想要创建一个消失的边界,该视图非常有用。如果你将borderWidth设置为0,边框将会消失,图像仍然保持圆角,就像边界一样。也就是说,它看起来就像边界完全由图像边缘绘制。

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.RectF
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView


class RoundedImageViewWithBorder @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0) : AppCompatImageView(context, attrs, defStyleAttr) {

    var borderColor: Int = 0
        set(value) {
            invalidate()
            field = value
        }
    var borderWidth: Int = 0
        set(value) {
            invalidate()
            field = value
        }
    var cornerRadius: Float = 0f
        set(value) {
            invalidate()
            field = value
        }

    private var bitmapForDraw: Bitmap? = null
    private var canvasForDraw: Canvas? = null
    private val transparentPaint = Paint().apply {
        isAntiAlias = true
        color = Color.TRANSPARENT
        style = Paint.Style.STROKE
        xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC)
    }

    private val borderPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.STROKE
    }

    private val transparentAreaRect = RectF()
    private val borderRect = RectF()

    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundedImageViewWithBorder)

        try {
            borderWidth = typedArray.getDimensionPixelSize(R.styleable.RoundedImageViewWithBorder_border_width, 0)
            borderColor = typedArray.getColor(R.styleable.RoundedImageViewWithBorder_border_color, 0)
            cornerRadius = typedArray.getDimensionPixelSize(R.styleable.RoundedImageViewWithBorder_corner_radius, 0).toFloat()

        } finally {
            typedArray.recycle()
        }
    }

    @SuppressLint("CanvasSize", "DrawAllocation")
    override fun onDraw(canvas: Canvas) {
        if (canvas.height <=0 || canvas.width <=0) {
            return
        }

        if (canvasForDraw?.height != canvas.height || canvasForDraw?.width != canvas.width) {
            val newBitmap = Bitmap.createBitmap(canvas.width, canvas.height, Bitmap.Config.ARGB_8888)
            bitmapForDraw = newBitmap
            canvasForDraw = Canvas(newBitmap)
        }
        
        bitmapForDraw?.eraseColor(Color.TRANSPARENT)

        // Draw existing content
        super.onDraw(canvasForDraw)

        if (borderWidth > 0) {
            canvasForDraw?.let { drawWithBorder(it) }
        } else {
            canvasForDraw?.let { drawWithoutBorder(it) }
        }

        // Draw everything on real canvas
        bitmapForDraw?.let { canvas.drawBitmap(it, 0f, 0f, null) }
    }

    private fun drawWithBorder(canvas: Canvas) {
        // Draw transparent area
        transparentPaint.strokeWidth = borderWidth.toFloat() * 4
        transparentAreaRect.apply {
            left = -borderWidth.toFloat() * 1.5f
            top = -borderWidth.toFloat() * 1.5f
            right = canvas.width.toFloat() + borderWidth.toFloat() * 1.5f
            bottom = canvas.height.toFloat() + borderWidth.toFloat() * 1.5f
        }
        canvasForDraw?.drawRoundRect(transparentAreaRect, borderWidth.toFloat() * 2 + cornerRadius, borderWidth.toFloat() * 2 + cornerRadius, transparentPaint)

        // Draw border
        borderPaint.color = borderColor
        borderPaint.strokeWidth = borderWidth.toFloat()
        borderRect.apply {
            left = borderWidth.toFloat() / 2
            top = borderWidth.toFloat() / 2
            right = canvas.width.toFloat() - borderWidth.toFloat() / 2
            bottom = canvas.height.toFloat() - borderWidth.toFloat() / 2
        }
        canvas.drawRoundRect(borderRect, cornerRadius - borderWidth.toFloat() / 2, cornerRadius - borderWidth.toFloat() / 2, borderPaint)
    }

    private fun drawWithoutBorder(canvas: Canvas) {
        // Draw transparent area
        transparentPaint.strokeWidth = cornerRadius * 4
        transparentAreaRect.apply {
            left = -cornerRadius * 2
            top = -cornerRadius * 2
            right = canvas.width.toFloat() + cornerRadius * 2
            bottom = canvas.height.toFloat() + cornerRadius * 2
        }
        canvasForDraw?.drawRoundRect(transparentAreaRect, cornerRadius * 3, cornerRadius * 3, transparentPaint)
    }

}

值:

<declare-styleable name="RoundedImageViewWithBorder">
    <attr name="corner_radius" format="dimension|string" />
    <attr name="border_width" format="dimension|reference" />
    <attr name="border_color" format="color|reference" />
</declare-styleable>

您应该扩展ImageView并绘制自己的圆角矩形。

如果你想在图像周围添加一个框架,你也可以在布局中将圆形框架叠加在图像视图的顶部。

例如,通过使用FrameLayout将帧叠加到原始图像上。FrameLayout的第一个元素将是你想要显示的图像。然后添加另一个ImageView与框架。第二个ImageView将显示在原始ImageView的顶部,因此Android将在原始ImageView上方绘制它的内容。

这是相当晚的响应,但对于任何其他人正在寻找这个,您可以执行以下代码手动圆角的图像。

http://www.ruibm.com/?p=184

这不是我的代码,但我用过它,它的工作非常出色。我将它用作ImageHelper类中的一个助手,并对它进行了一点点扩展,以便传入给定图像所需的羽化量。

最终代码如下所示:

package com.company.app.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;

public class ImageHelper {
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }
}