在Android中,ImageView默认是矩形的。如何将它变成圆角矩形(剪切Bitmap的四个角成为圆角矩形)?
请注意,从2021年起,只需使用ShapeableImageView
即可。
在Android中,ImageView默认是矩形的。如何将它变成圆角矩形(剪切Bitmap的四个角成为圆角矩形)?
请注意,从2021年起,只需使用ShapeableImageView
即可。
虽然回应有些晚了,但对于其他需要这个功能的人来说,你可以使用以下代码手动调整图像边角。
这不是我的代码,但我已经使用过它,效果非常好。我将其用作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;
}
}
另一种简单的方法是使用带有圆角和内部 ImageView 的 CardView:
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="8dp"
android:layout_margin="5dp"
android:elevation="10dp">
<ImageView
android:id="@+id/roundedImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/image"
android:background="@color/white"
android:scaleType="centerCrop"
/>
</androidx.cardview.widget.CardView>
API 21新增了基于圆角形状进行剪辑的功能,可在View
类中使用。
只需按照以下步骤:
res/drawable/round_outline.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
...
</shape>
android:background="@drawable/round_outline"
android:clipToOutline="true"
即可实现。不幸的是,存在一个Bug,该XML属性无法被识别。幸运的是,我们仍然可以在Java中设置剪辑:
ImageView.setClipToOutline(true)
它看起来会像这样:
注意:
此方法适用于任何 Drawable形状(不仅仅是圆形)。它将把ImageView剪裁成您在Drawable xml中定义的任何形状轮廓。
关于ImageView的特殊说明
setClipToOutline()
仅在View的背景设置为形状Drawable时才适用。如果存在此背景形状,则视图将此形状的轮廓用作剪辑和阴影的边框。
这意味着,如果您想使用setClipToOutline()
来使ImageView的角落变圆,您必须使用android:src
而不是android:background
设置图片(因为背景必须设置为您的圆形形状)。如果你一定要使用背景来设置你的图像而不是src,你可以使用以下解决方法:
android:clipToOutline
,必须使用android:outlineProvider="background"
。 - WindRiderImageView.setClipToOutline(true)
。 - Khaled Saifullah从Material Components Library的版本1.2.0-alpha03
开始,新增了ShapeableImageView
。
您可以使用类似以下的代码:
<com.google.android.material.imageview.ShapeableImageView
...
app:shapeAppearanceOverlay="@style/roundedImageView"
app:srcCompat="@drawable/ic_image" />
在你的themes.xml
文件中:
<style name="roundedImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">8dp</item>
</style>
或者以编程方式:
float radius = getResources().getDimension(R.dimen.default_corner_radius);
imageView.setShapeAppearanceModel(imageView.getShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius)
.build());
clip
Modifier
并应用 RoundedCornerShape
:Image(
painter = painterResource(R.drawable.xxxx),
contentDescription = "xxxx",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clip(RoundedCornerShape(8.dp))
)
虽然上面的答案可行,但Android核心开发人员Romain Guy在他的博客中展示了一种更好的方法,通过使用着色器而不是创建位图副本来使用更少的内存。其功能的基本要点如下:
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);
我已经基于此代码创建了RoundedImageView,将此逻辑封装到一个ImageView中,并添加了适当的ScaleType
支持和可选的圆角边框。
setCornerRadius(float cornerRadius)
因此,从Bitmap src
和目标 ImageView
开始,它看起来会像这样:
RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(res, src);
dr.setCornerRadius(cornerRadius);
imageView.setImageDrawable(dr);
android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
,所以 v4
也支持它。 - deadfishv4
支持库中,但是直到支持库的REVISION 21
版本才有。 - tyczjscaleType
为 centerCrop
(支持库v25.3.1)。 - rocknow<android.support.v7.widget.CardView
android:layout_width="40dp"
android:layout_height="40dp"
app:cardElevation="0dp"
app:cardCornerRadius="4dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rounded_user_image"
android:scaleType="fitXY"/>
</android.support.v7.widget.CardView>
您可以在 CardView 上设置所需的宽度、高度和半径,并在 ImageView 上设置 scaleType。
使用 AndroidX,使用 <androidx.cardview.widget.CardView>
。
centerCrop
。 - YellowJ我已经使用自定义ImageView完成了:
public class RoundRectCornerImageView extends ImageView {
private float radius = 18.0f;
private Path path;
private RectF rect;
public RoundRectCornerImageView(Context context) {
super(context);
init();
}
public RoundRectCornerImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundRectCornerImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
path = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
rect = new RectF(0, 0, this.getWidth(), this.getHeight());
path.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(path);
super.onDraw(canvas);
}
}
使用方法:
<com.mypackage.RoundRectCornerImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/image"
android:scaleType="fitXY" />
输出:
希望这对你有所帮助。
android:background
的图像集,而不适用于android:src
。 - CoolMind我发现这两种方法对于得出一个可行的解决方案非常有帮助。下面是我的综合版本,它是像素无关的,并且允许您在一些方角中使用相同的半径而其余的圆角则具有相同的半径(这是通常的用例)。感谢上面两种解决方案。
public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels , int w , int h , boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR ) {
Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final float densityMultiplier = context.getResources().getDisplayMetrics().density;
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);
//make sure that our rounded corner is scaled appropriately
final float roundPx = pixels*densityMultiplier;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
//draw rectangles over the corners we want to be square
if (squareTL ){
canvas.drawRect(0, h/2, w/2, h, paint);
}
if (squareTR ){
canvas.drawRect(w/2, h/2, w, h, paint);
}
if (squareBL ){
canvas.drawRect(0, 0, w/2, h/2, paint);
}
if (squareBR ){
canvas.drawRect(w/2, 0, w, h/2, paint);
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(input, 0,0, paint);
return output;
}
此外,我重写了ImageView以便在xml中定义它。你可能想添加一些超级调用的逻辑,但是我已经将其注释掉了,因为在我的情况下没什么帮助。
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
Drawable drawable = getDrawable();
Bitmap b = ((BitmapDrawable)drawable).getBitmap() ;
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth(), h = getHeight();
Bitmap roundBitmap = CropImageView.getRoundedCornerBitmap( getContext(), bitmap,10 , w, h , true, false,true, false);
canvas.drawBitmap(roundBitmap, 0,0 , null);
}
希望这能有所帮助!
Bitmap b = ((BitmapDrawable)drawable).getBitmap();
时,我遇到了NullPointerException异常。有什么解决方案吗? - Geek Guy圆形图像使用 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
库。
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);