Android 如何制作带有圆角的 ImageView?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2459916/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:55:45  来源:igfitidea点击:

How to make an ImageView with rounded corners?

androidimageviewandroid-imageviewandroid-imagerounded-corners

提问by michael

In Android, an ImageView is a rectangle by default. How can I make it a rounded rectangle (clip off all 4 corners of my Bitmap to be rounded rectangles) in the ImageView?

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

采纳答案by George Walters II

This is pretty late in response, but for anyone else that is looking for this, you can do the following code to manually round the corners of your images.

这是响应的很晚,但对于正在寻找它的其他人,您可以执行以下代码来手动圆化图像的角。

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

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

This isn't my code, but I've used it and it's works wonderfully. I used it as a helper within an ImageHelper class and extended it just a bit to pass in the amount of feathering I need for a given image.

这不是我的代码,但我已经使用过它并且效果很好。我将它用作 ImageHelper 类中的助手,并稍微扩展它以传递给定图像所需的羽化量。

Final code looks like this:

最终代码如下所示:

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

Hope this helps someone!

希望这可以帮助某人!

回答by vinc3m1

While the above answer works, Romain Guy (a core Android developer) shows a better methodin his blog which uses less memory by using a shader not creating a copy of the bitmap. The general gist of the functionality is here:

虽然上述答案有效,但 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);

The advantages of this over other methods is that it:

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

  • does not create a separate copy of the bitmap,which uses a lot of memory with large images [vs most of the other answers here]
  • supports antialisasing[vs clipPath method]
  • supports alpha[vs xfermode+porterduff method]
  • supports hardware acceleration[vs clipPath method]
  • only draws once to the canvas[vs xfermode and clippath methods]
  • 不创建位图的单独副本,它使用大量内存来处理大图像[与此处的大多数其他答案相比]
  • 支持抗锯齿[vs clipPath 方法]
  • 支持alpha[vs xfermode+porterduff 方法]
  • 支持硬件加速【vs clipPath方法】
  • 在画布上绘制一次[vs xfermode 和 clippath 方法]

I've created a RoundedImageViewbased off this code that wraps this logic into an ImageView and adds proper ScaleTypesupport and an optional rounded border.

我已经根据这段代码创建了一个RoundedImageView,它将这个逻辑包装到一个 ImageView 中,并添加了适当的ScaleType支持和一个可选的圆角边框。

回答by Taras Vovkovych

Another easy way is to use a CardView with the corner radius and an ImageView inside:

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

  <android.support.v7.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"
                />
        </android.support.v7.widget.CardView>

enter image description here

在此处输入图片说明

回答by hungryghost

Clipping to rounded shapes was added to the Viewclass in API 21.

ViewAPI 21 中的类中添加了裁剪为圆形。

Just do this:

只需这样做:

  • Create a rounded shape drawable, something like this:
  • 创建一个圆形可绘制对象,如下所示:

res/drawable/round_outline.xml

res/drawable/round_outline.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="10dp" />
    ...
</shape>
  • Set the drawable as your ImageView's background: android:background="@drawable/round_outline"
  • According to this documentation, then all you need to do is add android:clipToOutline="true"
  • 将 drawable 设置为 ImageView 的背景: android:background="@drawable/round_outline"
  • 根据这个文档,那么您需要做的就是添加android:clipToOutline="true"

Unfortunately, there's a bugand that XML attribute is not recognized. Luckily, we can still set up clipping in Java:

不幸的是,存在一个错误,无法识别 XML 属性。幸运的是,我们仍然可以在 Java 中设置剪辑:

  • In your activity or fragment: ImageView.setClipToOutline(true)
  • 在您的活动或片段中: ImageView.setClipToOutline(true)

Here's what it will look like:

这是它的样子:

enter image description here

在此处输入图片说明

Note:

笔记:

This method works for anydrawable shape (not just rounded). It will clip the ImageView to whatever shape outline you've defined in your Drawable xml.

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

Special note about ImageViews

关于 ImageViews 的特别说明

setClipToOutline()only works when the View's background is set to a shape drawable. If this background shape exists, View treats the shape's outline as the borders for clipping and shadowing purposes.

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

This means, if you want to use setClipToOutline()to round the corners on an ImageView, your image must be set using android:srcinstead of android:background(since background must be set to your rounded shape). If you MUST use background to set your image instead of src, you can use this workaround:

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

  • Create a layout and set its background to your shape drawable
  • Wrap that layout around your ImageView (with no padding)
  • The ImageView (including anything else in the layout) will now display with rounded layout shape.
  • 创建布局并将其背景设置为可绘制的形状
  • 将该布局包裹在 ImageView 周围(无填充)
  • ImageView(包括布局中的任何其他内容)现在将以圆形布局形状显示。

回答by tyczj

In the v21 of the Support library there is now a solution to this: it's called RoundedBitmapDrawable.

在支持库的 v21 中,现在有一个解决方案:它称为RoundedBitmapDrawable

It's basically just like a normal Drawable except you give it a corner radius for the clipping with:

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

setCornerRadius(float cornerRadius)

So, starting with Bitmap srcand a target ImageView, it would look something like this:

所以,从Bitmap src和一个 target 开始ImageView,它看起来像这样:

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

回答by Hiren Patel

I have done by Custom ImageView:

我已经通过自定义 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);
    }
}

How to use:

如何使用:

<com.mypackage.RoundRectCornerImageView
     android:id="@+id/imageView"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@drawable/image"
     android:scaleType="fitXY" />

Output:

输出:

enter image description here

在此处输入图片说明

Hope this would help you.

希望这会帮助你。

回答by Chirag Mittal

A quick xml solution -

一个快速的 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>

You can set your desired width, height and radius on CardView and scaleType on ImageView.

您可以在 CardView 和 ImageView 上的 scaleType 上设置所需的宽度、高度和半径。

With AndroidX, use <androidx.cardview.widget.CardView>

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

回答by Caspar Harmer

I found that both methods were very helpful in coming up with a working solution. Here is my composite version, that is pixel independent and allows you to have some square corners with the rest of the corners having the same radius (which is the usual use case). With thanks to both of the solutions above:

我发现这两种方法都非常有助于提出有效的解决方案。这是我的复合版本,它与像素无关,并允许您有一些方角,其余角具有相同的半径(这是通常的用例)。感谢上述两种解决方案:

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

Also, I overrode ImageView to put this in so I could define it in xml. You may want to add in some of the logic that the super call makes here, but I've commented it as it's not helpful in my case.

此外,我覆盖了 ImageView 将其放入以便我可以在 xml 中定义它。您可能想在此处添加 super 调用所做的一些逻辑,但我已对其进行了评论,因为它对我的情况没有帮助。

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

Hope this helps!

希望这可以帮助!

回答by shailesh

Rounded image Using ImageLoaderhere

圆形图像在此处使用ImageLoader

Create DisplayImageOptions:

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

Or you can user PicassoLibrary from Square.

或者您可以使用PicassoSquare 的 Library。

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

you can download RoundedTransformation file here here

你可以在这里下载 RoundedTransformation 文件

回答by Christian

As all the answers seemed too complicated for me just for round corners I thought and came to another solution which I think is worth to share, just with XML in case you have some space around the image:

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

Create a bordered shape with transparent content like this:

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

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

Then in a RelativeLayout you can first place your image and then in the same location above the shape with another ImageView. The cover-shape should be larger in size by the amount of the border width. Be careful to take a larger corner radius as the outer radius is defined but the inner radius is what covers your image.

然后在 RelativeLayout 中,您可以首先放置图像,然后与另一个 ImageView 放在形状上方的相同位置。封面形状的尺寸应该比边框宽度大。小心采用更大的角半径,因为外半径已定义,但内半径覆盖了您的图像。

Hope it helps somebody, too.

希望它也能帮助某人。

Editas per CQM request the relative layout example:

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