How to make an ImageView with rounded corners?

前端 未结 30 2538
天涯浪人
天涯浪人 2020-11-21 05:39

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?

相关标签:
30条回答
  • 2020-11-21 06:23

    Clipping to rounded shapes was added to the View class in API 21.

    Just do this:

    • Create a rounded shape drawable, something like this:

    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"

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

    • In your activity or fragment: ImageView.setClipToOutline(true)

    Here's what it will look like:

    enter image description here

    Note:

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

    Special note about 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.

    This means, if you want to use setClipToOutline() to round the corners on an ImageView, your image must be set using android:src instead 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:

    • 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.
    0 讨论(0)
  • 2020-11-21 06:24

    There is a cool library that allows you to shape imageviews.

    Here is an example:

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

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

    Result:

    0 讨论(0)
  • 2020-11-21 06:25

    Starting with the version 1.2.0-alpha03 of the the Material Components Library there is the new ShapeableImageView.

    You can use something like:

      <com.google.android.material.imageview.ShapeableImageView
          ...
          app:shapeAppearanceOverlay="@style/roundedImageView"
          app:srcCompat="@drawable/ic_image" />
    

    with:

      <style name="roundedImageView" parent="">
        <item name="cornerFamily">rounded</item>
        <item name="cornerSize">8dp</item>
      </style>
    

    Or programmatically:

    float radius = getResources().getDimension(R.dimen.default_corner_radius);
    imageView.setShapeAppearanceModel(imageView.getShapeAppearanceModel()
        .toBuilder()
        .setAllCorners(CornerFamily.ROUNDED,radius)
        .build());
    

    0 讨论(0)
  • 2020-11-21 06:25

    My implementation of ImageView with rounded corners widget, that (down||up)sizes image to required dimensions. It utilizes code form 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);
    
        }
    
    }
    
    0 讨论(0)
  • 2020-11-21 06:27

    As of recently, there is another way - using Glide's Generated API. It takes some initial work but then gives you all the power of Glide with the flexibility to do anything because you writhe the actual code so I think it's a good solution for the long run. Plus, the usage is very simple and neat.

    First, setup Glide version 4+:

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

    Then create Glid's app module class to trigger the annotation processing:

    @GlideModule
    public final class MyAppGlideModule extends AppGlideModule {}
    

    Then create the Glide extension which actually does the work. You can customize it to do whatever you want:

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

    After adding these files, build your project.

    Then use it in your code like this:

    GlideApp.with(this)
            .load(imageUrl)
            .roundedCorners(getApplicationContext(), 5)
            .into(imageView);
    
    0 讨论(0)
  • 2020-11-21 06:28

    While the above answer works, Romain Guy (a core Android developer) shows a better method in 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:

    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]

    I've created a RoundedImageView based off this code that wraps this logic into an ImageView and adds proper ScaleType support and an optional rounded border.

    0 讨论(0)
提交回复
热议问题