如何使一个图像视图与圆角?

在Android中,ImageView默认为矩形。如何在ImageView中使其成为圆角矩形(将位图的所有4个角剪掉为圆角矩形)?


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

670795 次浏览

您应该扩展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;
}
}

下面创建一个圆角矩形布局对象,该对象围绕放置在其中的任何子对象绘制圆角矩形。它还演示了如何在不使用布局xml文件的情况下以编程方式创建视图和布局。

package android.example;


import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;


public class MessageScreen extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int mainBackgroundColor = Color.parseColor("#2E8B57");
int labelTextColor = Color.parseColor("#FF4500");
int messageBackgroundColor = Color.parseColor("#3300FF");
int messageTextColor = Color.parseColor("#FFFF00");


DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
int minMarginSize = Math.round(density * 8);
int paddingSize = minMarginSize * 2;
int maxMarginSize = minMarginSize * 4;


TextView label = new TextView(this);
/*
* The LayoutParams are instructions to the Layout that will contain the
* View for laying out the View, so you need to use the LayoutParams of
* the Layout that will contain the View.
*/
LinearLayout.LayoutParams labelLayoutParams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
label.setLayoutParams(labelLayoutParams);
label.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
label.setPadding(paddingSize, paddingSize, paddingSize, paddingSize);
label.setText(R.string.title);
label.setTextColor(labelTextColor);


TextView message = new TextView(this);
RoundedRectangle.LayoutParams messageLayoutParams = new RoundedRectangle.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
/*
* This is one of the calls must made to force a ViewGroup to call its
* draw method instead of just calling the draw method of its children.
* This tells the RoundedRectangle to put some extra space around the
* View.
*/
messageLayoutParams.setMargins(minMarginSize, paddingSize,
minMarginSize, maxMarginSize);
message.setLayoutParams(messageLayoutParams);
message.setTextSize(TypedValue.COMPLEX_UNIT_SP, paddingSize);
message.setText(R.string.message);
message.setTextColor(messageTextColor);
message.setBackgroundColor(messageBackgroundColor);


RoundedRectangle messageContainer = new RoundedRectangle(this);
LinearLayout.LayoutParams messageContainerLayoutParams = new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
messageContainerLayoutParams.setMargins(paddingSize, 0, paddingSize, 0);
messageContainer.setLayoutParams(messageContainerLayoutParams);
messageContainer.setOrientation(LinearLayout.VERTICAL);
/*
* This is one of the calls must made to force a ViewGroup to call its
* draw method instead of just calling the draw method of its children.
* This tells the RoundedRectangle to color the the exta space that was
* put around the View as well as the View. This is exterior color of
* the RoundedRectangle.
*/
messageContainer.setBackgroundColor(mainBackgroundColor);
/*
* This is one of the calls must made to force a ViewGroup to call its
* draw method instead of just calling the draw method of its children.
* This is the interior color of the RoundedRectangle. It must be
* different than the exterior color of the RoundedRectangle or the
* RoundedRectangle will not call its draw method.
*/
messageContainer.setInteriorColor(messageBackgroundColor);
// Add the message to the RoundedRectangle.
messageContainer.addView(message);


//
LinearLayout main = new LinearLayout(this);
LinearLayout.LayoutParams mainLayoutParams = new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
main.setLayoutParams(mainLayoutParams);
main.setOrientation(LinearLayout.VERTICAL);
main.setBackgroundColor(mainBackgroundColor);
main.addView(label);
main.addView(messageContainer);


setContentView(main);
}
}

RoundedRectangle布局对象的类如下所定义:

/**
*  A LinearLayout that draws a rounded rectangle around the child View that was added to it.
*/
package android.example;


import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.LinearLayout;


/**
* A LinearLayout that has rounded corners instead of square corners.
*
* @author Danny Remington
*
* @see LinearLayout
*
*/
public class RoundedRectangle extends LinearLayout {
private int mInteriorColor;


public RoundedRectangle(Context p_context) {
super(p_context);
}


public RoundedRectangle(Context p_context, AttributeSet attributeSet) {
super(p_context, attributeSet);
}


// Listener for the onDraw event that occurs when the Layout is drawn.
protected void onDraw(Canvas canvas) {
Rect rect = new Rect(0, 0, getWidth(), getHeight());
RectF rectF = new RectF(rect);
DisplayMetrics metrics = new DisplayMetrics();
Activity activity = (Activity) getContext();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
int arcSize = Math.round(density * 10);


Paint paint = new Paint();
paint.setColor(mInteriorColor);


canvas.drawRoundRect(rectF, arcSize, arcSize, paint);
}


/**
* Set the background color to use inside the RoundedRectangle.
*
* @param Primitive int - The color inside the rounded rectangle.
*/
public void setInteriorColor(int interiorColor) {
mInteriorColor = interiorColor;
}


/**
* Get the background color used inside the RoundedRectangle.
*
* @return Primitive int - The color inside the rounded rectangle.
*/
public int getInteriorColor() {
return mInteriorColor;
}


}

上面提到的乔治·沃尔特斯二世的道具,我只是接受了他的答案,并将其扩展了一点,以支持不同的圆角。这可以进一步优化(一些目标矩形重叠),但不是很多。

我知道这个线程有点旧,但它是Google上查询如何在Android上旋转ImageViews角落的热门结果之一。

/**
* Use this method to scale a bitmap and give it specific rounded corners.
* @param context Context object used to ascertain display density.
* @param bitmap The original bitmap that will be scaled and have rounded corners applied to it.
* @param upperLeft Corner radius for upper left.
* @param upperRight Corner radius for upper right.
* @param lowerRight Corner radius for lower right.
* @param lowerLeft Corner radius for lower left.
* @param endWidth Width to which to scale original bitmap.
* @param endHeight Height to which to scale original bitmap.
* @return Scaled bitmap with rounded corners.
*/
public static Bitmap getRoundedCornerBitmap(Context context, Bitmap bitmap, float upperLeft,
float upperRight, float lowerRight, float lowerLeft, int endWidth,
int endHeight) {
float densityMultiplier = context.getResources().getDisplayMetrics().density;


// scale incoming bitmap to appropriate px size given arguments and display dpi
bitmap = Bitmap.createScaledBitmap(bitmap,
Math.round(endWidth * densityMultiplier),
Math.round(endHeight * densityMultiplier), true);


// create empty bitmap for drawing
Bitmap output = Bitmap.createBitmap(
Math.round(endWidth * densityMultiplier),
Math.round(endHeight * densityMultiplier), Config.ARGB_8888);


// get canvas for empty bitmap
Canvas canvas = new Canvas(output);
int width = canvas.getWidth();
int height = canvas.getHeight();


// scale the rounded corners appropriately given dpi
upperLeft *= densityMultiplier;
upperRight *= densityMultiplier;
lowerRight *= densityMultiplier;
lowerLeft *= densityMultiplier;


Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);


// fill the canvas with transparency
canvas.drawARGB(0, 0, 0, 0);


// draw the rounded corners around the image rect. clockwise, starting in upper left.
canvas.drawCircle(upperLeft, upperLeft, upperLeft, paint);
canvas.drawCircle(width - upperRight, upperRight, upperRight, paint);
canvas.drawCircle(width - lowerRight, height - lowerRight, lowerRight, paint);
canvas.drawCircle(lowerLeft, height - lowerLeft, lowerLeft, paint);


// fill in all the gaps between circles. clockwise, starting at top.
RectF rectT = new RectF(upperLeft, 0, width - upperRight, height / 2);
RectF rectR = new RectF(width / 2, upperRight, width, height - lowerRight);
RectF rectB = new RectF(lowerLeft, height / 2, width - lowerRight, height);
RectF rectL = new RectF(0, upperLeft, width / 2, height - lowerLeft);


canvas.drawRect(rectT, paint);
canvas.drawRect(rectR, paint);
canvas.drawRect(rectB, paint);
canvas.drawRect(rectL, paint);


// set up the rect for the image
Rect imageRect = new Rect(0, 0, width, height);


// set up paint object such that it only paints on Color.WHITE
paint.setXfermode(new AvoidXfermode(Color.WHITE, 255, AvoidXfermode.Mode.TARGET));


// draw resized bitmap onto imageRect in canvas, using paint as configured above
canvas.drawBitmap(bitmap, imageRect, imageRect, paint);


return output;
}

我发现这两种方法在提出工作解决方案方面都非常有帮助。这是我的复合版本,与像素无关,允许您拥有一些正方形角,其余角具有相同的半径(这是通常的用例)。 由于上述两种解决方案:

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

希望这有帮助!

我实现的带有圆角小部件的ImageView,它(向下||向上)将图像大小调整到所需的尺寸。它使用代码形式CaspNZ。

public class ImageViewRounded extends ImageView {


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


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


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


@Override
protected void onDraw(Canvas canvas) {
BitmapDrawable drawable = (BitmapDrawable) getDrawable();


if (drawable == null) {
return;
}


if (getWidth() == 0 || getHeight() == 0) {
return;
}


Bitmap fullSizeBitmap = drawable.getBitmap();


int scaledWidth = getMeasuredWidth();
int scaledHeight = getMeasuredHeight();


Bitmap mScaledBitmap;
if (scaledWidth == fullSizeBitmap.getWidth() && scaledHeight == fullSizeBitmap.getHeight()) {
mScaledBitmap = fullSizeBitmap;
} else {
mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap, scaledWidth, scaledHeight, true /* filter */);
}


Bitmap roundBitmap = ImageUtilities.getRoundedCornerBitmap(getContext(), mScaledBitmap, 5, scaledWidth, scaledHeight,
false, false, false, false);
canvas.drawBitmap(roundBitmap, 0, 0, null);


}


}

非常感谢第一个答案。这是修改后的版本,将矩形图像转换为正方形图像(并四舍五入),并将填充颜色作为参数传递。

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

为什么不在draw()中进行剪辑?

以下是我的解决方案:

  • 通过裁剪扩展RelativeLayout
  • 将ImageView(或其他视图)放入布局:

代码:

public class RoundRelativeLayout extends RelativeLayout {


private final float radius;


public RoundRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);


TypedArray attrArray = context.obtainStyledAttributes(attrs,
R.styleable.RoundRelativeLayout);
radius = attrArray.getDimension(
R.styleable.RoundRelativeLayout_radius, 0);
}


private boolean isPathValid;
private final Path path = new Path();


private Path getRoundRectPath() {
if (isPathValid) {
return path;
}


path.reset();


int width = getWidth();
int height = getHeight();
RectF bounds = new RectF(0, 0, width, height);


path.addRoundRect(bounds, radius, radius, Direction.CCW);
isPathValid = true;
return path;
}


@Override
protected void dispatchDraw(Canvas canvas) {
canvas.clipPath(getRoundRectPath());
super.dispatchDraw(canvas);
}


@Override
public void draw(Canvas canvas) {
canvas.clipPath(getRoundRectPath());
super.draw(canvas);
}


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {


int oldWidth = getMeasuredWidth();
int oldHeight = getMeasuredHeight();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);


int newWidth = getMeasuredWidth();
int newHeight = getMeasuredHeight();
if (newWidth != oldWidth || newHeight != oldHeight) {
isPathValid = false;
}
}


}

虽然上述答案有效,但Romain Guy(Android核心开发人员)在他的博客中显示了更好的方法,它通过使用着色器而不是创建位图副本来使用更少的内存。该功能的一般要点在这里:

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

与其他方法相比,它的优点在于:

  • 不创建位图的单独副本,使用大量内存和大型图像[与这里的大多数其他答案相比]
  • 支持打压[vs clipPath方法]
  • 支持alpha[vs xfermode+porterduff方法]
  • 支持硬件加速[vs clipPath方法]
  • 在画布上画一次[vs xfermode和clippath方法]

我基于此代码创建了一个图像取景,它将此逻辑包装到ImageView中,并添加了适当的ScaleType支持和可选的圆形边框。

罗曼·盖伊就在那里。

缩小版如下。

Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.image)).getBitmap();


Bitmap bitmapRounded = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), 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, bitmap.getWidth(), bitmap.getHeight())), 10, 10, paint);


imageView.setImageBitmap(bitmapRounded);

将形状应用于您的imageView,如下所示:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#faf5e6" />
<stroke
android:width="1dp"
android:color="#808080" />
<corners android:radius="15dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
</shape>

这可能对你的朋友有帮助。

这不是确切的答案,但这是一个类似的解决方案。它可能会帮助那些和我在同一条船上的人。

我的图像,一个应用程序徽标,有一个透明的背景,我应用XML渐变作为图像背景。我在XML中为ImageView添加了必要的填充/边距,然后将其添加为我的背景:

<?xml version="1.0" encoding="utf-8"?>
<!-- This file defines the gradient used on the background of the main activity. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:type="linear"
android:startColor="@color/app_color_light_background"
android:endColor="@color/app_color_disabled"
android:angle="90" />


<!-- Round the top corners. -->
<corners
android:topLeftRadius="@dimen/radius_small"
android:topRightRadius="@dimen/radius_small" />
</shape>
</item>
</selector>

由于所有的答案对我来说都太复杂了,只是为了圆角,我想到了另一个我认为值得分享的解决方案,只是使用XML,以防您在图像周围有一些空间:

创建一个带有透明内容的边框形状,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="30dp" />
<stroke
android:color="#ffffffff"
android:width="10dp" />
</shape>

然后在RelativeLayout中,您可以首先放置图像,然后使用另一个ImageView将图像放置在形状上方的相同位置。封面形状的大小应大于边框宽度。请注意,由于定义了外半径,但内半径是覆盖图像的半径,因此需要采用更大的角半径。

希望它也能帮助到别人。

编辑按照CQM请求相对布局示例:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >


<ImageView
android:id="@+id/imageToShow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/imgCorners"
android:layout_alignLeft="@+id/imgCorners"
android:layout_alignRight="@+id/imgCorners"
android:layout_alignTop="@+id/imgCorners"
android:background="#ffffff"
android:contentDescription="@string/desc"
android:padding="5dp"
android:scaleType="centerCrop" />


<ImageView
android:id="@+id/imgCorners"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@string/desc"
android:src="@drawable/corners_white" />


</RelativeLayout>

使用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);

您可以在此处下载圆形转换文件 这里

相当多的答案!

我遵循了这个例子,有些人也有点建议:http://www.techrepublic.com/article/pro-tip-round-corners-on-an-android-imageview-with-this-hack/

然而,我需要的是一个彩色的圆圈,在一个透明的图像后面。对于任何有兴趣做同样事情的人…

1)将FrameLayout设置为宽度和高度-在我的情况下是图像的大小(50dp)。
2)将具有src="@Drawable/…"的ImageView放置在具有图像的ImageView上方。给它一个ID,在我的情况下,我称它为图标形状
3)可绘制的mask.xml应具有纯色#ffffffff 4)如果您想动态更改代码中的圆圈颜色,请执行

ImageView iv2 = (ImageView) v.findViewById(R.id.iconShape);
Drawable shape = getResources().getDrawable(R.drawable.mask);
shape.setColorFilter(Color.BLUE, Mode.MULTIPLY);
iv2.setImageDrawable(shape);

这个纯xml解决方案在我的情况下已经足够好了。http://www.techrepublic.com/article/pro-tip-round-corners-on-an-android-imageview-with-this-hack/

编辑

以下是一个简单的答案:

在 /res/drawable文件夹中,创建一个frame.xml文件。在其中,我们定义了一个带有圆角和透明中心的简单矩形。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#00ffffff" />
<padding android:left="6dp"
android:top="6dp"
android:right="6dp"
android:bottom="6dp" />
<corners android:radius="12dp" />
<stroke android:width="6dp" android:color="#ffffffff" />
</shape>

在您的布局文件中,您添加了一个包含标准ImageView以及嵌套FrameLayout的LinearLayout。FrameLayout使用填充和自定义绘图来提供圆角的错觉。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center"
android:background="#ffffffff">


<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dp"
android:src="@drawable/tr"/>


<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">


<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="6dp"
android:src="@drawable/tr"/>


<ImageView
android:src="@drawable/frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />


</FrameLayout>


</LinearLayout>

在支持库的v21中,现在有一个解决方案:它被称为可绘制圆角位图

它基本上就像一个普通的Drawable,除了你给它一个角半径的剪辑:

setCornerRadius(float cornerRadius)

因此,从Bitmap src和目标ImageView开始,它看起来像这样:

RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(res, src);
dr.setCornerRadius(cornerRadius);
imageView.setImageDrawable(dr);

你可以试试这个库-图像取景

它是:

支持圆角、椭圆和圆形的快速ImageView。CircleImageView的超集。

我在我的项目中使用过它,它非常简单。

使用它来获取具有边界的圆形图像-

    public static Bitmap getCircularBitmapWithBorder(Bitmap bitmap, int bordercolor) {
if (bitmap == null || bitmap.isRecycled()) {
return null;
}
int borderWidth=(int)(bitmap.getWidth()/40);
final int width = bitmap.getWidth() + borderWidth;
final int height = bitmap.getHeight() + borderWidth;


Bitmap canvasBitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP,
TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);


Canvas canvas = new Canvas(canvasBitmap);
float radius = width > height ? ((float) height) / 2f
: ((float) width) / 2f;
canvas.drawCircle(width / 2, height / 2, radius, paint);
paint.setShader(null);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(bordercolor);
paint.setStrokeWidth(borderWidth);
canvas.drawCircle(width / 2, height / 2, radius - borderWidth / 2,
paint);
return canvasBitmap;
}

在布局让你的ImageView像:

<com.example..CircularImageView
android:id="@+id/profile_image_round_corner"
android:layout_width="80dp"
android:layout_height="80dp"
android:scaleType="fitCenter"
android:padding="2dp"
android:background="@null"
android:adjustViewBounds="true"
android:layout_centerInParent="true"
android:src="@drawable/dummy"
/>

并创建一个类

package com.example;


import java.util.Formatter.BigDecimalLayoutForm;


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;


public class CircularImageView extends ImageView {


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


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


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


@Override
protected void onDraw(Canvas canvas) {


Drawable drawable = getDrawable();


if (drawable == null) {
return;
}


if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);


int w = getWidth(), h = getHeight();


Bitmap roundBitmap = getRoundBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);


}


public static Bitmap getRoundBitmap(Bitmap bmp, int radius) {
Bitmap sBmp;


if (bmp.getWidth() != radius || bmp.getHeight() != radius) {
float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
float factor = smallest / radius;
sBmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / factor), (int)(bmp.getHeight() / factor), false);
} else {
sBmp = bmp;
}


Bitmap output = Bitmap.createBitmap(radius, radius, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xffa19774;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, radius, radius);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(radius / 2 + 0.7f,
radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sBmp, rect, rect, paint);


return output;
}


}

裁剪为圆形形状已添加到API 21中的View类中。

只要这样做:

  • 创建一个可绘制的圆形形状,如下所示:

资源/可绘制/round_outline.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
...
</shape>
  • 将可绘制对象设置为ImageView的背景: android:background="@drawable/round_outline"
  • 根据这个留档,那么你需要做的就是添加android:clipToOutline="true"

不幸的是,有一个bug并且无法识别该XML属性。幸运的是,我们仍然可以在Java中设置剪辑:

  • 在您的活动或片段中:ImageView.setClipToOutline(true)

这是它会是什么样子:

输入图片描述

备注:

此方法适用于任何可绘制形状(不仅仅是圆形)。它会将ImageView剪辑为您在Drawable xml中定义的任何形状轮廓。

关于ImageViews的特别说明

setClipToOutline()仅在View的背景设置为可绘制的形状时有效。如果此背景形状存在,View会将该形状的轮廓视为边框,用于剪辑和阴影。

这意味着,如果您想使用setClipToOutline()来圆化ImageView上的角,则必须使用android:src而不是android:background设置图像(因为背景必须设置为圆形形状)。如果您必须使用背景而不是src来设置图像,您可以使用此解决方法:

  • 创建布局并将其背景设置为可绘制的形状
  • 将布局包裹在ImageView周围(没有填充)
  • ImageView(包括布局中的任何其他内容)现在将显示圆形布局形状。

如果你们中的任何人是面临这个问题

输入图片描述

很可能,您使用的是androidStudio。由于图像重新调整大小和Android Studio中的所有内容,您可能会遇到此问题。此问题的一个简单解决方案是减小drawCircle()中的圆半径。在我的情况下,我使用此修复程序

使用canvas.drawCircle(100, 100, 90, paint);而不是canvas.drawCircle(100, 100, 100, paint);肯定会解决您的问题。

以下是最后编辑的代码:-

  public class Profile extends ActionBarActivity {




TextView username;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.profile);




username= (TextView) findViewById(R.id.txt);


String recievedusername=getIntent().getExtras().getString("toname");
username.setText(recievedusername);




Bitmap bm = BitmapFactory.decodeResource(getResources(),
R.mipmap.gomez);


Bitmap resizedBitmap = Bitmap.createScaledBitmap(bm, 200,200, false);
Bitmap conv_bm=getCircleBitmap(resizedBitmap,100);
// set circle bitmap
ImageView mImage = (ImageView) findViewById(R.id.profile_image);
mImage.setImageBitmap(conv_bm);
// TODO Auto-generated method stub
}
private Bitmap getCircleBitmap(Bitmap bitmap , int pixels) {
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
final 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);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(100,100, 90, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
bitmap.recycle();
return output;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_apploud, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_addnew) {
Intent i;
i=new Intent(Profile.this,ApplaudSomeone.class);
startActivity(i);
return true;
}
return super.onOptionsItemSelected(item);
}
}

试试这个

Bitmap finalBitmap;
if (bitmap.getWidth() != radius || bitmap.getHeight() != radius)
finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius,
false);
else
finalBitmap = bitmap;
Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
finalBitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);


final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, finalBitmap.getWidth(),
finalBitmap.getHeight());


paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(finalBitmap.getWidth() / 2 + 0.7f,
finalBitmap.getHeight() / 2 + 0.7f,
finalBitmap.getWidth() / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(
android.graphics.PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(finalBitmap, rect, rect, paint);


return output;
    /**
* Background Async task to load user profile picture from url
*/
private class LoadProfileImage extends AsyncTask<String, Void, RoundedBitmapDrawable> {
ImageView profileImageView;


public LoadProfileImage(ImageView profileImageView) {
this.profileImageView = profileImageView;
}


protected RoundedBitmapDrawable doInBackground(String... urls) {
String photoUrl = urls[0];
RoundedBitmapDrawable profileRoundedDrawable = null;
try {
InputStream inputStream = new java.net.URL(photoUrl).openStream();
Resources res = getResources();


profileRoundedDrawable = RoundedBitmapDrawableFactory.create(res, inputStream);
profileRoundedDrawable.setCircular(true);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return profileRoundedDrawable;
}


protected void onPostExecute(RoundedBitmapDrawable result) {
profileImageView.setImageDrawable(result);
}
}

这里是一个简单的例子覆盖ImageView,然后你也可以在布局设计器中使用它来预览。

public class RoundedImageView extends ImageView {


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


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


public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}


@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}


@Override
public void setImageDrawable(Drawable drawable) {
float radius = 0.1f;
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
RoundedBitmapDrawable rid = RoundedBitmapDrawableFactory.create(getResources(), bitmap);
rid.setCornerRadius(bitmap.getWidth() * radius);
super.setImageDrawable(rid);
}
}

这是快速解决方案。半径用于所有角落,并基于位图宽度的百分比。

我刚刚覆盖了setImageDrawable并使用支持v4方法来绘制圆角位图。

用法:

<com.example.widgets.RoundedImageView
android:layout_width="39dp"
android:layout_height="39dp"
android:src="@drawable/your_drawable" />

使用ImageView和自定义ImageView预览:

在此处输入图片描述

重定向到此处的问题的答案: “如何在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;
}

滑翔库和圆角位图可绘制工厂类的帮助下,很容易实现。您可能需要创建圆形占位符图像。

    Glide.with(context)
.load(imgUrl)
.asBitmap()
.placeholder(R.drawable.placeholder)
.error(R.drawable.placeholder)
.into(new BitmapImageViewTarget(imgProfilePicture) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(),
Bitmap.createScaledBitmap(resource, 50, 50, false));
drawable.setCornerRadius(10); //drawable.setCircular(true);
imgProfilePicture.setImageDrawable(drawable);
}
});

我通过Custom 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" />

输出:

在此处输入图片描述

希望这对你有帮助。

如果您的图像在互联网上,最好的方法是使用滑翔和RoundedBitmapDrawableFactory(来自API 21-但在支持库中可用),如下所示:

 Glide.with(ctx).load(url).asBitmap().centerCrop().into(new BitmapImageViewTarget(imageView) {
@Override
protected void setResource(Bitmap res) {
RoundedBitmapDrawable bitmapDrawable =
RoundedBitmapDrawableFactory.create(ctx.getResources(), res);
bitmapDrawable.setCircular(true);//comment this line and uncomment the next line if you dont want it fully cricular
//circularBitmapDrawable.setCornerRadius(cornerRadius);
imageView.setImageDrawable(bitmapDrawable);
}
});

虽然前两个答案有效,但我想描述更多。 假设,你的ImageView所在的地方有一个活动或片段。你希望绘制一张图像并按比例缩放它。然后你应该在onCreate或onCreateView中编写以下内容:

LinearLayout rootLayout = (LinearLayout) findViewById(R.id.rootLayout);
ImageView image = (ImageView) findViewById(R.id.image);
// Wait till an activity is visible and image can be measured.
rootLayout.post(new Runnable() {
@Override
public void run() {
// Setting ImageView height with aspect ratio.
Drawable drawable = ContextCompat.getDrawable(getActivity(), R.drawable.your_image);
int height = getImageViewHeight(drawable, image);


// Rounding image corners.
float radius = getResources().getDimension(R.dimen.your_radius_in_dp);
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
Bitmap result = getRoundedBitmap(bitmap, image.getWidth(), height, radius);
image.setImageBitmap(result);
}
});

其中设置新图像高度为:

public static int getImageViewHeight(Drawable drawable, ImageView imageView) {
imageView.setImageDrawable(drawable);
int width = drawable.getIntrinsicWidth();
int height = 0;
if (width > 0) {
height = (drawable.getIntrinsicHeight() * imageView.getWidth()) / width;
imageView.getLayoutParams().height = height;
imageView.requestLayout();
}
return height;
}

然后您应该编写一个方法来缩放图像并对其角进行圆角。这里的宽度和高度是位图的新维度(更小或更大)。在下面的示例中,我只圈两个顶角

private Bitmap getRoundedBitmap(Bitmap bitmap, int width, int height, float radius) {
// Create scaled bitmap.
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
BitmapShader shader = new BitmapShader(scaledBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);


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


Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
// First make all corners round.
canvas.drawRoundRect(new RectF(0, 0, width, height), radius, radius, paint);
// Then draw bottom rectangle.
canvas.drawRect(0, height - radius, radius, height, paint);
canvas.drawRect(width - radius, height - radius, width, height, paint);
return result;
}

另一种简单的方法是使用带有角半径的CardView和内部的ImageView:

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

在此处输入图片描述

我正在使用一个自定义视图,我在其他视图的顶部布局,并且就画4个小倒角与背景颜色相同。

优点:

  • 不分配位图。
  • 适用于任何你想要应用圆角的视图。
  • 适用于所有 API级别;)

代码:

public class RoundedCornersView extends View {
private float mRadius;
private int mColor = Color.WHITE;
private Paint mPaint;
private Path mPath;


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


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


TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.RoundedCornersView,
0, 0);


try {
setRadius(a.getDimension(R.styleable.RoundedCornersView_radius, 0));
setColor(a.getColor(R.styleable.RoundedCornersView_cornersColor, Color.WHITE));
} finally {
a.recycle();
}
}


private void init() {
setColor(mColor);
setRadius(mRadius);
}


private void setColor(int color) {
mColor = color;
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);


invalidate();
}


private void setRadius(float radius) {
mRadius = radius;
RectF r = new RectF(0, 0, 2 * mRadius, 2 * mRadius);
mPath = new Path();
mPath.moveTo(0,0);
mPath.lineTo(0, mRadius);
mPath.arcTo(r, 180, 90);
mPath.lineTo(0,0);
invalidate();
}


@Override
protected void onDraw(Canvas canvas) {


/*This just draws 4 little inverted corners */


int w = getWidth();
int h = getHeight();
canvas.drawPath(mPath, mPaint);
canvas.save();
canvas.translate(w, 0);
canvas.rotate(90);
canvas.drawPath(mPath, mPaint);
canvas.restore();
canvas.save();
canvas.translate(w, h);
canvas.rotate(180);
canvas.drawPath(mPath, mPaint);
canvas.restore();
canvas.translate(0, h);
canvas.rotate(270);
canvas.drawPath(mPath, mPaint);
}
}

如果您正在使用Glide Library,这将很有帮助:

Glide.with(getApplicationContext())
.load(image_url)
.asBitmap()
.centerCrop()
.into(new BitmapImageViewTarget(imageView) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(getApplicationContext().getResources(), resource);
circularBitmapDrawable.setCornerRadius(dpToPx(10));
circularBitmapDrawable.setAntiAlias(true);
imageView.setImageDrawable(circularBitmapDrawable);
}
});




public int dpToPx(int dp) {
DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}

这是我的解决方案:

<com.myproject.ui.RadiusCornerImageView
android:id="@+id/imageViewPhoto"
android:layout_width="160dp"
android:layout_height="160dp"
app:corner_radius_dp="5"
app:corner_radius_position="top"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

在java代码中:

public class RadiusCornerImageView extends android.support.v7.widget.AppCompatImageView {
private int cornerRadiusDP = 0; // dp
private int corner_radius_position;


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


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


public RadiusCornerImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RadiusCornerImageView, 0, 0);
try {
cornerRadiusDP = typeArray.getInt(R.styleable.RadiusCornerImageView_corner_radius_dp, 0);
corner_radius_position = typeArray.getInteger(R.styleable.RadiusCornerImageView_corner_radius_position, 0);
} finally {
typeArray.recycle();
}
}


@Override
protected void onDraw(Canvas canvas) {
float radiusPx = AndroidUtil.dpToPx(getContext(), cornerRadiusDP);
Path clipPath = new Path();
RectF rect = null;
if (corner_radius_position == 0) { // all
// round corners on all 4 angles
rect = new RectF(0, 0, this.getWidth(), this.getHeight());
} else if (corner_radius_position == 1) {
// round corners only on top left and top right
rect = new RectF(0, 0, this.getWidth(), this.getHeight() + radiusPx);


} else {
throw new IllegalArgumentException("Unknown corner_radius_position = " + corner_radius_position);
}
clipPath.addRoundRect(rect, radiusPx, radiusPx, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
}
}

感谢melanke,您可以使用自定义类并创建自定义循环ImageView

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;


public class MLRoundedImageView extends android.support.v7.widget.AppCompatImageView {


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


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


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


@Override
protected void onDraw(Canvas canvas) {


Drawable drawable = getDrawable();


if (drawable == null) {
return;
}


if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);


int w = getWidth(), h = getHeight();


Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);


}


public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
Bitmap sbmp;


if (bmp.getWidth() != radius || bmp.getHeight() != radius) {
float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
float factor = smallest / radius;
sbmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / factor), (int)(bmp.getHeight() / factor), false);
} else {
sbmp = bmp;
}


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


final int color = 0xffa19774;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, radius, radius);


paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(radius / 2 + 0.7f,
radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sbmp, rect, rect, paint);


return output;
}


}

然后在XML中使用它,例如:

<your.package.name.MLRoundedImageView
..
/>

来源

静态编程语言

import android.graphics.BitmapFactory
import android.os.Bundle
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
import kotlinx.android.synthetic.main.activity_main.*


val bitmap = BitmapFactory.decodeResource(resources, R.drawable.myImage)
val rounded = RoundedBitmapDrawableFactory.create(resources, bitmap)
rounded.cornerRadius = 20f
profileImageView.setImageDrawable(rounded)

要使ImageView循环,我们可以更改cornerRadius

rounded.isCircular = true

最近,还有另一种方法-使用Glide生成的API。它需要一些初始工作,但随后为您提供了Glide的所有功能,并且可以灵活地做任何事情,因为您可以编写实际代码,所以我认为从长远来看这是一个很好的解决方案。另外,用法非常简单整洁。

首先,设置滑翔版本4+:

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

然后创建G的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);

您只能在布局中使用ImageView,使用glide,您可以使用此方法应用圆角。

首先在你的格拉德尔写,

compile 'com.github.bumptech.glide:glide:3.7.0'

对于圆角的图像,

public void loadImageWithCorners(String url, ImageView view) {
Glide.with(context)
.load(url)
.asBitmap()
.centerCrop()
.placeholder(R.color.gray)
.error(R.color.gray)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new BitmapImageViewTarget(view) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(context.getResources(), resource);
circularBitmapDrawable.setCornerRadius(32.0f); // radius for corners
view.setImageDrawable(circularBitmapDrawable);
}
});
}

调用方法:

loadImageWithCorners("your url","your imageview");

对于使用Glide和静态编程语言的人,您可以通过扩展RequestBuilder来实现

fun <T> GlideRequest<T>.roundCorners(cornerRadius: Int) =
apply(RequestOptions().transform(RoundedCorners(cornerRadius)))

和使用;

 GlideApp.with(context)
.load(url)
.roundCorners(context.resources.getDimension(R.dimen.radius_in_dp).toInt())
.into(imgView)

有一个酷库可以让你塑造图像视图。

下面是一个例子:

<com.github.siyamed.shapeimageview.mask.PorterShapeImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:siShape="@drawable/shape_rounded_rectangle"
android:src="@drawable/neo"
app:siSquare="true"/>

形状定义:

<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:topLeftRadius="18dp"
android:topRightRadius="18dp"
android:bottomLeftRadius="18dp"
android:bottomRightRadius="18dp" />
<solid android:color="@color/black" />
</shape>

结果:

结果

一个快速的xml解决方案-

<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上设置所需的宽度、高度和半径。

使用AndroidX,使用<androidx.cardview.widget.CardView>

对于滑翔4. x. x

使用这个简单的代码

Glide
.with(context)
.load(uri)
.apply(
RequestOptions()
.circleCrop())
.into(imageView)

您可以非常轻松地使用roundedImageView库:

compile 'com.makeramen:roundedimageview:2.3.0'

然后:

<com.makeramen.roundedimageview.RoundedImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/img_episode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="7dp"
app:riv_border_color="@color/colorPrimary"
app:riv_border_width="1dip"
app:riv_corner_radius="10dip"
app:riv_mutate_background="true"
/>

我使用Path仅在图像Canvas上绘制角落。(我需要没有位图内存分配的解决方案)

@Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);


if (!hasRoundedCorners()) return;


mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(0);


Path path = new Path();
path.setFillType(Path.FillType.INVERSE_WINDING);
path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), mRadius, mRadius, Path.Direction.CCW);
canvas.drawPath(path, mPaint);
}

请注意,您不应该在onDraw方法中分配任何新对象。此代码是概念证明,不应在产品代码中这样使用

查看更多: https://medium.com/@przemek.materna/rounded-image-view-no-bitmap-reallocation-11a8b163484d

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

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


}

对我来说,以下解决方案似乎是最优雅的:

ImageView roundedImageView = new ImageView (getContext());
roundedImageView.setClipToOutline(true);
Bitmap bitmap = AppUtil.decodeSampledBitmapFromResource(new File(valueListItemsView.getImagePath()), width, height);
roundedImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
roundedImageView.setImageBitmap(bitmap);
roundedImageView.setBackgroundResource(R.drawable.rounded_corner);

rounded_corner.xml的代码是:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/colorAccent" />
<corners android:radius="24dp" />
</shape>

静态编程语言版本:

@GlideExtension
object GamersGeekGlideExtension {


@NonNull
@JvmStatic
@GlideOption
fun roundedCorners(options: BaseRequestOptions<*>, context: Context, cornerRadius: Int): BaseRequestOptions<*> {
val px =
(cornerRadius * (context.resources.displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)).roundToInt()
return options.transforms(RoundedCorners(px))
}
}

注意:Glide扩展现在需要BaseRequest estOptions而不是Request estOptions。此外,它的功能与刚刚在kotlin中转换的@Sir Codesalot答案相同。

可以使用以下形状轻松完成。将其作为src添加到您的图像中。 如果您想删除边框,只需将背景颜色添加到边框即可 ;-)

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/img_area_one"
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />


<item>
<shape
android:padding="10dp"
android:shape="rectangle">
<corners
android:topLeftRadius="8dp"
android:topRightRadius="8dp"
/>
<stroke
android:width="5dp"
android:color="@color/white" />
</shape>
</item>
</layer-list>

材料组件库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());

在此处输入图片描述


使用jetpack组成,您可以使用#E YZ 2应用#E YZ 0Modifier

Image(
painter = painterResource(R.drawable.xxxx),
contentDescription = "xxxx",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clip(RoundedCornerShape(8.dp))
)

答案中提供的方法都不适合我。如果您的Android版本为5.0或更高版本,我发现以下方法有效:

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


ViewOutlineProvider provider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
int curveRadius = 24;
outline.setRoundRect(0, 0, view.getWidth(), (view.getHeight()+curveRadius), curveRadius);
}
};
imageview.setOutlineProvider(provider);
imageview.setClipToOutline(true);
}

没有要定义的xml形状,上面的代码仅为top创建角,普通方法无法工作。如果您需要4个角被圆角,请删除:

"+ curveRadius"

从setRoundRect中的底部参数。您可以通过指定适合您需要的轮廓来进一步将形状扩展为任何其他形状。查看以下链接:

Android开发者文档


请注意,与Android中的任何度量一样,您必须“转换”通常来自DP的大小。在上面的示例中,假设您希望半径为24

                            int curveRadius = 24;

例如,您可能稍后在可绘制对象中添加边框,半径设置为“24”,并且您希望它匹配。因此,

    float desiredRadius = 24;
float radiusConverted = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
desiredRadius,
itemView.getContext().getResources().getDisplayMetrics());

然后

                            int curveRadius = radiusConverted;

我认为最简单的解决方案是这样的:-

步骤1-创建一个形状可绘制文件,如下所示:-

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


<solid android:color="@color/white" />


<corners android:radius="@dimen/dimen_10dp" />


<stroke
android:width="1dp"
android:color="@color/white" />
</shape>

第2步-在代码中使用上述绘图。

Drawable drawable = ContextCompat.getDrawable(mActivity, R.drawable.photos_round_shape);
drawable.mutate().setColorFilter(randomColor, PorterDuff.Mode.SRC_ATOP);
imageView.setBackground(drawable);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
imageView.setClipToOutline(true);
}


Glide.with(mContext)
.setDefaultRequestOptions(getNoAnimationOptions())
.load(url)
.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>

用于在代码下方使用圆角边框

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

您可以使用较新版本的Android材质库中提供的新形状图

为此,您首先需要在应用级别build.gradle文件中添加以下依赖项

implementation 'com.google.android.material:material:<version>'

此外,请确保此应用程序级别build.gradle文件具有Google的Maven存储库google(),如下所示

allprojects {
repositories {
google()
jcenter()
}

}

在此之后,您可以引用这个资源来实现所需类型或形状的图像视图。

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

Coil是静态编程语言优先,使用现代库,包括Coroutines、OkHttp、Okio和AndroidX生命周期。

github链接

尝试材料组件库并使用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())

输入图片描述

***这个问题很老,我知道,但这里有另一种更简单的四舍五入图像的方法:

这是一种程序化的方法。

创造你的空虚和…

} public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) { Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.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(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint); return output;

加载您的图像,然后设置圆角

imageview1.setImageResource(R.drawable.yourimage);


Bitmap bm = ((android.graphics.drawable.BitmapDrawable) imageview1.getDrawable()).getBitmap();
imageview1.setImageBitmap(getRoundedCornerBitmap(bm, 30));

30是你的半径,你会得到这样的东西:

圆形图像/图标示例

别管我的图像看起来如何,它是一个放大的小图标

它可以使用ShapeAppearanceOverlay使用ShapeableImageView完成:

<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/avatar"
android:layout_width="64dp"
android:layout_height="64dp"
android:padding="4dp"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"/>

其中样式ShapeAppearanceOverlay.Avatar驻留在res/values/styles.xml中:

<style name="ShapeAppearanceOverlay.Avatar" parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">50%</item>
</style>

这只需要等于layout_heightlayout_width设置,否则将是一个没有圆圈的药丸。