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


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


当前回答

对于圆形边界使用下面的代码

  <com.google.android.material.card.MaterialCardView
                        android:id="@+id/circle"
                        android:layout_width="45dp"
                        android:layout_height="45dp"
                        android:layout_marginStart="5dp"

                        app:cardCornerRadius="25dp"
                        app:strokeColor="@color/colorDarkGreen"

                        app:strokeWidth="1dp">

                        <ImageView
                            android:id="@+id/toolbarProfile"
                            android:scaleType="fitXY"

                            android:layout_width="match_parent"
                            android:layout_height="match_parent"

                            android:src="@drawable/avater" />
                    </com.google.android.material.card.MaterialCardView>

其他回答

尝试材质组件库并使用ShapeableImageView。 大概是这样的:

Java:

imageView=new ShapeableImageView(context);
imageView.setShapeAppearanceModel(
        imageView.getShapeAppearanceModel()
                 .toBuilder()
                 .setAllCornerSizes(20)
                 .build());

芬兰湾的科特林:

val imageView = ShapeableImageView(context)
imageView.setShapeAppearanceModel(
        imageView.getShapeAppearanceModel()
                 .toBuilder()
                 .setAllCornerSizes(20f)
                 .build())

这里要回答的问题是: 如何在Android中创建一个圆形ImageView ?

public static Bitmap getRoundBitmap(Bitmap bitmap) {

    int min = Math.min(bitmap.getWidth(), bitmap.getHeight());

    Bitmap bitmapRounded = Bitmap.createBitmap(min, min, bitmap.getConfig());

    Canvas canvas = new Canvas(bitmapRounded);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    canvas.drawRoundRect((new RectF(0.0f, 0.0f, min, min)), min/2, min/2, paint);

    return bitmapRounded;
}

如果你不希望边框影响图像,使用这个类。不幸的是,我没有找到任何方法来绘制画布上的透明区域来到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>

这里使用ImageLoader

创建DisplayImageOptions:

DisplayImageOptions options = new DisplayImageOptions.Builder()
    // this will make circle, pass the width of image 
    .displayer(new RoundedBitmapDisplayer(getResources().getDimensionPixelSize(R.dimen.image_dimen_menu))) 
    .cacheOnDisc(true)
    .build();

imageLoader.displayImage(url_for_image,ImageView,options);

或者你也可以从Square上使用毕加索图书馆。

Picasso.with(mContext)
    .load(com.app.utility.Constants.BASE_URL+b.image)
    .placeholder(R.drawable.profile)
    .error(R.drawable.profile)
    .transform(new RoundedTransformation(50, 4))
    .resizeDimen(R.dimen.list_detail_image_size, R.dimen.list_detail_image_size)
    .centerCrop()
    .into(v.im_user);

你可以在这里下载RoundedTransformation文件 在这里

我建议在这种情况下使用Coil库

Coil是Kotlin-first,使用现代库,包括Coroutines, OkHttp, Okio和AndroidX Lifecycles。

github链接