在ImageView中显示带圆角的位图

51

我有一个ImageView,我想让它带有圆角

我使用了以下代码:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> 
    <solid  android:color="@null"/>    

    <stroke android:width="1dp"
            android:color="#ff000000"/>


    <corners android:radius="62px"/> 
</shape>

将这段代码设置为我的ImageView的背景。

虽然它能够工作,但是我放在ImageView上的源图片超出了边界,而且不能自适应到新形状。如何解决这个问题?


请查看此链接,可能会有所帮助:http://stackoverflow.com/questions/16695023/how-to-create-a-background-with-image-rounded-corners-without-borders/16695407#16695407。 - Raghunandan
为您的 ImageView 设置 padding 应该可以解决这个问题。 - user2652394
13个回答

87

试试这个:

public class CustomImageView extends ImageView {

    public static float radius = 18.0f;  

    public CustomImageView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onDraw(Canvas canvas) {
        //float radius = 36.0f;  
        Path clipPath = new Path();
        RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
        clipPath.addRoundRect(rect, radius, radius, Path.Direction.CW);
        canvas.clipPath(clipPath);
        super.onDraw(canvas);
    }
}

<your.pack.name.CustomImageView
                android:id="@+id/selectIcon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:scaleType="centerCrop" />

CustomImageView  iconImage = (CustomImageView )findViewById(R.id.selectIcon);
iconImage.setImageBitmap(bitmap);

或者,

ImageView iv= new CustomImageView(this);
iv.setImageResource(R.drawable.pic);

1
谢谢@Anand分享这个,但是我没有得到圆形的锐利边缘,请问!您能指导一下我,40X40 dp的图像大小应该使用什么半径? - swiftBoy
1
一般情况下,在绘制或布局方法中不应进行对象分配。将这些分配移到视图对象的其他部分相当简单。 - greg7gkb
对我来说最好的解决方案。简单而聪明。 - Eliasz Kubala
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - 김준호
我使用了这个类,但是角落不够平滑。你能建议我应该怎么做来使角落变得更加平滑吗? - Vivek Pratap Singh
显示剩余3条评论

38

奇怪的是,这里没有人提到来自Android Support Library v4的RoundedBitmapDrawable。对我来说,这是最简单的获得无边框圆角的方法。以下是使用示例:

RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(getResources(), bitmap);
final float roundPx = (float) bitmap.getWidth() * 0.06f;
roundedBitmapDrawable.setCornerRadius(roundPx);

我有一个问题...设置圆角半径会导致图像位置改变!请自行尝试:设置RoundedBitmapDrawable的边界>在不设置圆角半径的情况下查看结果。现在再设置圆角半径,再次查看结果! - S.M.Mousavi
如此简单而完整 - Mehdi Khademloo
2
值得注意的是,您不能使用此可绘制对象的位图进行进一步处理,因为它不是圆形的。 - Ultimo_m
终于!所有其他解决方案都不允许我拥有一个既有圆角按钮又有圆角背景的设计。 - ConcernedHobbit

24

编写一个函数,使用canvas将位图进行圆角处理。

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;
}

了解更多信息:这里


这很整洁!(如果似乎无法正常工作,请确保大幅增加像素计数) - Sagar
我正在画阴影位图到画布上,为了使阴影圆角化,这是我的步骤:mPaint.setShadowLayer(radius, dX, dY, shadowColor);canvas.drawRoundRect(rect, cornerRadius, cornerRadius, mPaint); 并使用您的代码使位图角变圆,但是 shadowbitmap 的角不同,我该怎么办? - Vivek Thummar

9

被接受的答案使用路径裁剪,但它不支持抗锯齿。请参见Romain Guy在他的帖子中的评论。"path clipping does not support antialiasing and you get jagged edges."

http://www.curious-creature.com/2012/12/11/android-recipe-1-image-with-rounded-corners/

有一个好的库(vinc3m1's RoundedImageView)可以在ImageView上支持圆角,但它只支持每个角相同的半径。因此,我做了一个可以在每个角上设置不同半径的库。

它不依赖于路径裁剪或重绘。它只是用canvas.drawPath()方法画一次。所以我最终得到了我想要的结果,就像下面这样。

enter image description here

查看:https://github.com/pungrue26/SelectableRoundedImageView


7

对我而言,以下方法可以实现这个效果。 :) 该方法接受一个位图对象,并返回带有圆角的位图对象。roundPx是您想要的圆角像素数:

public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
    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 = 12;

    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;
}

你可以使用这个库来代替ImageView,无需进行任何额外的编码。


抄袭:https://dev59.com/xHE95IYBdhLWcg3wGZ9_#3292810。 - CristiFati

6
如果您需要制作具有不同角半径的位图,我建议按照以下代码操作:
private static Bitmap createRoundedRectBitmap(@NonNull Bitmap bitmap,
                                float topLeftCorner, float topRightCorner,
                                float bottomRightCorner, float bottomLeftCorner) {
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), 
                                        Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final int color = Color.WHITE;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
    final RectF rectF = new RectF(rect);
    Path path = new Path();
    float[] radii = new float[]{
            topLeftCorner, bottomLeftCorner,
            topRightCorner, topRightCorner,
            bottomRightCorner, bottomRightCorner,
            bottomLeftCorner, bottomLeftCorner
    };

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    path.addRoundRect(rectF, radii, Path.Direction.CW);
    canvas.drawPath(path, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);
    return output;
}

第二个元素应该是topLeftCorner而不是bottomLeftCorner,这样它就可以工作了。 - Saint

4
如果您需要边框,可以使用一个带有透明背景和白色边框的圆角盒子图像。例如: Rounded box 然后将其与目标图像一起使用,如下所示:
<FrameLayout
android:layout_width="100px"
android:layout_height="100px" >
<ImageView
        android:id="@+id/targetImage"
        android:layout_width="100px"
        android:layout_height="100px"
        android:src="@drawable/app_icon"
        android:layout_gravity="center" />
<ImageView
        android:id="@+id/boxImage"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitXY"
        android:src="@drawable/box" />

  1. CardView作为ImageView的父布局也是一个不错的解决方案。

3
可以使用背景drawable来实现,就像很多帖子中解释的那样,但还需要设置裁剪。这是一个完整的示例代码:
AppCompatImageView iconView = findViewById(R.id.thumbnail);
iconView.setClipToOutline(true);

布局:
<android.support.v7.widget.AppCompatImageView
    android:id="@+id/thumbnail"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:contentDescription="@string/thumbnail"
    android:scaleType="centerInside"
    android:background="@drawable/round_view" <!--here set the drawable as background -->
    tools:src="@mipmap/ic_user" />

可绘制对象:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="10dp" />
</shape>

2
/**
 * Creates new circular bitmap based on original one.
 * @param newCornerRadius is optional
 */
fun Bitmap.toCircular(context: Context, newCornerRadius: Float? = null): RoundedBitmapDrawable {
    return RoundedBitmapDrawableFactory.create(context.resources, this).apply {
        isCircular = true
        newCornerRadius?.let {
            cornerRadius = it
        }
    }
}

0

Kotlin版本

fun Bitmap.roundCorner(pixels: Int): Bitmap {
        val output: Bitmap = Bitmap.createBitmap(
                width, height, Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(output)
        val color = -0xbdbdbe
        val paint = Paint()
        val rect = Rect(0, 0, width, height)
        val rectF = RectF(rect)
        val roundPx = pixels.toFloat()
        paint.isAntiAlias = true
        canvas.drawARGB(0, 0, 0, 0)
        paint.color = color
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(this, rect, rect, paint)
        return output
}

调用方式: sourceBitmap.roundCorner(60)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接