To draw Bitmap - Wrap content to Surface view in Android - android

I have created a custom surface view class with threads and I added the custom surface view in my main activity inside a relative layout. Now I declare a bitmap in the custom surface view class constructor.
public static Bitmap mbitmap;
public Surface(Context ctx, AttributeSet attrSet) {
super(ctx, attrSet);
context = ctx;
mbitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.abc);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
And I have drawn it in canvas
public void doDraw(Canvas canvas) {
canvas.drawBitmap(mbitmap, 0, 0, null);
}
I get the successful drawing. But it occupies the whole screen
<RelativeLayout
android:id="#+id/outer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.cg.Surface
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RelativeLayout
android:id="#+id/processing_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
</RelativeLayout>
even though I use Wrap_Content for Height and Width I get the whole screen drawn at the back. How to draw the bitmap image with appropriate size alone? Is that possible with this override method in Custom Surface View Class :
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
{ }
If no how to use setMeasuredDimension within it and restrict the size of surfaceview within the Bitmap?

We can use a rectangle, and draw an image inside it using Matrix, so we can achieve
public void doDraw(Canvas canvas)
{
int width = mbitmap.getWidth();
int height = mbitmap.getHeight();
float h= (float) height;
float w= (float) width;
Matrix mat=new Matrix();
mat.setTranslate( 500, 500 );
mat.setScale(800/w ,800/h);
canvas.drawBitmap(mbitmap, mat, null);
}

we can achieve that using the
public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint);
I mean :
canvas.drawBitmap(bitmap, src, dst, paint);
method in onDraw with
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + width, y + height);
makes it done I hope. I thought this might help others, since a long time I awaited to reach this solution of myself.

Related

Why path drawn on scaled GLES20RecordingCanvas and simple Canvas has different qualities?

Path drawn on scaled GLES20RecordingCanvas has quality as if it was drawn unscaled in bitmap and then up-scaled.
In contrast, if I create Canvas with backing bitmap and then apply the same scaling transformations to Canvas object I get much superior bitmap.
Here both circles are drawn with Path.addCircle and using Canvas.scale. Upper circle is drawn with scaled GLES20RecordingCanvas and lower is drawn with scaled simple Canvas with backing bitmap.
Some code:
public class TestPathRenderer extends View {
...
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
float distortedWidth = getDistortedWidth();
float distortedHeight = getDistortedHeight();
path.reset();
path.addCircle(distortedWidth/2f, distortedHeight/2f, Math.min(distortedWidth/2f, distortedHeight/2f), Path.Direction.CW);
bitmap = assembleNewBitmap(measuredWidth, measuredHeight);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (renderMode) {
case RENDER_MODE_WO_BITMAP:
drawOnCanvas(canvas);
break;
case RENDER_MODE_WITH_BITMAP:
canvas.drawBitmap(bitmap, 0f, 0f, paint);
break;
default:
throw new UnsupportedOperationException("Undefined render mode: " + renderMode);
}
}
private Bitmap assembleNewBitmap(int w, int h) {
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawOnCanvas(canvas);
return bitmap;
}
private void drawOnCanvas(#NonNull Canvas canvas) {
canvas.save();
canvas.scale(DISTORTION_FACTOR, DISTORTION_FACTOR);
canvas.drawPath(path, paint);
canvas.restore();
}
}
Full example
I can't understand the quality difference with these two cases. For me it seems that they have to be interchangeable.
Poor quality during scaling is a limitation of Hardware Acceleration according to Android docs.
After seeing your question, I decided to check out the source code of the GLES20RecordingCanvas class. And here's what I found out:
GLES20RecordingCanvas extends from GLES20Canvas which extends from HardwareCanvas. This HardwareCanvas class extends from Canvas. But the main difference I noticed is that it overrides the isHardwareAcceleratedMethod() returning true.
So my assumption is that the GLES20RecordingCanvas renders the bitmap with Hardware Acceleration while Canvas doesn't. And this is probably why you get less quality with the GLES20RecorgingCanvas.

Android inverse shape using xml [duplicate]

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?
Note that from 2021 onwards, simply use ShapeableImageView
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
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.
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;
}
}
Another easy way is to use a CardView with the corner radius and an ImageView inside:
<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>
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:
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.
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.
Starting with the version 1.2.0-alpha03 of 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 in your themes.xml:
<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());
With jetpack compose you can apply a clip Modifier using a RoundedCornerShape:
Image(
painter = painterResource(R.drawable.xxxx),
contentDescription = "xxxx",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clip(RoundedCornerShape(8.dp))
)
In the v21 of the Support library there is now a solution to this: it's called RoundedBitmapDrawable.
It's basically just like a normal Drawable except you give it a corner radius for the clipping with:
setCornerRadius(float cornerRadius)
So, starting with Bitmap src and a target ImageView, it would look something like this:
RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(res, src);
dr.setCornerRadius(cornerRadius);
imageView.setImageDrawable(dr);
A quick xml solution -
<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.
With AndroidX, use <androidx.cardview.widget.CardView>
I have done by 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);
}
}
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:
Hope this would help you.
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.
#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!
Rounded image Using ImageLoader here
Create 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 Picasso Library from Square.
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
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:
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.
Hope it helps somebody, too.
Edit as per CQM request the relative layout example:
<?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>
It can be done with a ShapeableImageView using a ShapeAppearanceOverlay:
<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"/>
Where style ShapeAppearanceOverlay.Avatar resides in res/values/styles.xml:
<style name="ShapeAppearanceOverlay.Avatar" parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">50%</item>
</style>
This just need equal layout_height and layout_width set, else with will be a pill an no circle.
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);
}
}
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);
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:
Try the Material Components Library and use the ShapeableImageView.
Somethig like this :
Java :
imageView=new ShapeableImageView(context);
imageView.setShapeAppearanceModel(
imageView.getShapeAppearanceModel()
.toBuilder()
.setAllCornerSizes(20)
.build());
Kotlin :
val imageView = ShapeableImageView(context)
imageView.setShapeAppearanceModel(
imageView.getShapeAppearanceModel()
.toBuilder()
.setAllCornerSizes(20f)
.build())
Here is a simple example overriding imageView, you can then also use it in layout designer to preview.
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);
}
}
This is for fast solution. Radius is used on all corners and is based of percentage of bitmap width.
I just overrided setImageDrawable and used support v4 method for rounded bitmap drawable.
Usage:
<com.example.widgets.RoundedImageView
android:layout_width="39dp"
android:layout_height="39dp"
android:src="#drawable/your_drawable" />
Preview with imageView and custom imageView:
Kotlin
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)
To make ImageView Circular we can change cornerRadius with:
rounded.isCircular = true
Apply a shape to your imageView as below:
<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>
it may be helpful to you friend.
You should extend ImageView and draw your own rounded rectangle.
If you want a frame around the image you could also superimpose the rounded frame on top of the image view in the layout.
[edit]Superimpose the frame on to op the original image, by using a FrameLayout for example. The first element of the FrameLayout will be the image you want to diplay rounded. Then add another ImageView with the frame. The second ImageView will be displayed on top of the original ImageView and thus Android will draw it's contents above the orignal ImageView.
Props to George Walters II above, I just took his answer and extended it a bit to support rounding individual corners differently. This could be optimized a bit further (some of the target rects overlap), but not a whole lot.
I know this thread is a bit old, but its one of the top results for queries on Google for how to round corners of ImageViews on Android.
/**
* 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;
}
Romain Guy is where it's at.
Minified version as follows.
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);
Why not do clipping in draw()?
Here is my solution:
Extend RelativeLayout with clipping
Put ImageView (or other views) into the layout:
Code:
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;
}
}
}
This pure xml solution was good enough in my case. http://www.techrepublic.com/article/pro-tip-round-corners-on-an-android-imageview-with-this-hack/
EDIT
Here's the answer in a nutshell:
In the /res/drawable folder, create a frame.xml file. In it, we define a simple rectangle with rounded corners and a transparent center.
<?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>
In your layout file you add a LinearLayout that contains a standard ImageView, as well as a nested FrameLayout. The FrameLayout uses padding and the custom drawable to give the illusion of rounded corners.
<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>
None of the methods provided in the answers worked for me. I found the following way works if your android version is 5.0 or above:
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);
}
No xml shapes to be defined, and the code above create corners only for top, which normal methods won't work. If you need 4 corners to be rounded, remove:
"+ curveRadius"
From the parameter for bottom in setRoundRect. You can further expand the shape to any others by specifying outlines that suit your needs. Check out the following link:
Android Developer Documentation.
Note, as with any measure in Android, you have to "convert" the size typically from DP. In the example above, say you want the radius to be 24
int curveRadius = 24;
For example you may be later adding a border in a drawable with the radius set as "24" and you wish it to match. Hence,
float desiredRadius = 24;
float radiusConverted = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
desiredRadius,
itemView.getContext().getResources().getDisplayMetrics());
and then
int curveRadius = radiusConverted;
The following creates a rounded rectangle layout object that draws a rounded rectangle around any child objects that are placed in it. It also demonstrates how to create views and layouts programmatically without using the layout xml files.
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);
}
}
The class for RoundedRectangle layout object is as defined here:
/**
* 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;
}
}
If you are using Glide Library this would be helpful:
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));
}
Thanks a lot to first answer. Here is modified version to convert a rectangular image into a square one (and rounded) and fill color is being passed as parameter.
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;
}
if your image is on internet the best way is using glide and RoundedBitmapDrawableFactory (from API 21 - but available in support library) like so:
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);
}
});
Answer for the question that is redirected here:
"How to create a circular ImageView in Android?"
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;
}

Custom view's onDraw receives canvas with different sizes

I have a class derived from ImageView:
public class TouchView extends ImageView
{
#Override
protected void onDraw(Canvas canvas)
...
The touchview is created only once in the activity's onCreate and populated with a drawable from a SVG file.
ImageView imageView = new TouchView(this);
imageView.setScaleType(ImageView.ScaleType.MATRIX);
FrameLayout f = (FrameLayout)findViewById(R.id.frame2);
FrameLayout.LayoutParams l = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT);
f.addView(imageView, l);
...
is = openFileInput(svgname);
svg = SVGParser.getSVGFromInputStream(is);
is.close();
Drawable d = svg.createPictureDrawable();
imageView.setImageDrawable(d);
All the environment remains the same all the time. Yet in the onDraw method I'm getting canvas with different sizes between the events. That is the code:
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Log.v("DRAW", " w= " + canvas.getWidth() + " h=" + canvas.getHeight());
...
}
produces logs with lines, where width and height of the canvas change back and forth from normal 1024*728 (this is the correct view dimension on the tablet) to 200*160 (strange thing introducing bugs in my drawings). I'm embarrassed.
Should the canvas be always of the same size for the same view/drawable? The documentation says that getWidth and getHeight methods return dimensions of the current drawing layer, but it's not clear what is the layer, how many of them is created for the canvas "behind the scene" and how to control this process.
I'd appreciate any explanation on how to get consistent drawing behaviuor, specifically by getting actual size of the view being painted in onDraw.
Currently I'm using a workround with a call to the view's getDrawingRect, but I'm not sure it is a proper way, because it seems that the canvas parameter of onDraw should be all-sufficient for drawing sizing.
I had the same issue, here is how I got this fixed, hope it helps you
protected void onDraw(Canvas c) {
super.onDraw(c);
int w = getWidth(), h = getHeight();
// resize
Matrix resize = new Matrix();
resize.postScale((float)Math.min(w, h) / (float)mMarker.getWidth(), (float)Math.min(w, h) / (float)mMarker.getHeight());
imageScaled = Bitmap.createBitmap(mMarker, 0, 0, mMarker.getWidth(), mMarker.getHeight(), resize, false);
c.drawBitmap(imageScaled, 0,0, paint);
}
Where mMarker is defined in the custom ImageView constructor.
...
private Bitmap mMarker, imageScaled;
Paint paint = new Paint();
//Java constructor
public AvatarImageView(Context context) {
super(context);
init();
}
//XML constructor
public AvatarImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// load the image only once
mMarker = BitmapFactory.decodeResource(getResources(), R.drawable.silhouette_48);
mMarker.setHasAlpha(true);paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(4);
//invalidate(); // don't know if I need this
}

How to use custom views, e.g. setting drawable

I think I'm a bit confused about how to use custom views. I'm following along with slides from a talk given by Eric Burke from Square (from this year's anddevcon, slides here: http://www.andevcon.com/AndevCon_II/downloadpresentation.aspx?aid=Taming_Android__User_Experience_Lessons_from_Square_pdf.zip&sid=2).
His code, or at least the part he showed in the slides, went something like this:
public class EditablePhoto extends View {
private Bitmap framedPhoto;
private Bitmap image;
private Drawable placeholder;
public EditablePhoto(Context context) {
super(context);
}
#Override protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
//ensure view always square
int min = Math.min(measuredHeight, measuredWidth);
setMeasuredDimension(min, min);
}
#Override
protected void onDraw(Canvas canvas) {
if(placeholder == null && image==null) return;
if(framedPhoto == null) {
createFramedPhoto(Math.min(getWidth(), getHeight()));
}
canvas.drawBitmap(framedPhoto, 0, 0, null);
}
private void createFramedPhoto(int size) {
Drawable imageDrawable = (image!=null)
? new BitmapDrawable(image) : placeholder;
Bitmap output = Bitmap.createBitmap(size, size,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
RectF outerRect = new RectF(0, 0, size, size);
float outerRadius = size / 18f;
//Red rectangle
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
canvas.drawRoundRect(outerRect, outerRadius, outerRadius, paint);
paint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.SRC_IN));
imageDrawable.setBounds(0, 0, size, size);
canvas.saveLayer(outerRect, paint, Canvas.ALL_SAVE_FLAG);
imageDrawable.draw(canvas);
canvas.restore();
}
}
What I don't get is how to actually use this View now.... Where and when do you set the bitmaps, which are private fields in this class...?
Generally confused and would love some enlightenment.
More than one year passed, but I hope this will help anyone who looking for the right answer. In my case, I putted this line of code
framedPhoto = output;
as the last one in createFramedPhoto() method. It works.
In the example, the author created a rounded rectangle as background then he draw the bitmap on it with XOR mode, so all pixel outside the rounded rectangle will be trim off.
OnDraw() is the method where you will Draw your view on canvas. here too you can analyze onDraw() will fisrt call CreateFramePhoto then draw this Bitmap on canvas .
You can add this customView in layout Either from xml or in Java Class
1) Through Xml :
<EditablePhoto android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
..........................
/>
dont forgate to add constructor EditablePhoto(Context context, AttributeSet attributeSet) for this case
2) through Java class :
EditablePhoto editablePhoto = new EditablePhoto(this);
addView(editablePhoto) // or do anthing you want with this

Android-RoundCorner for a imageView [duplicate]

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?
Note that from 2021 onwards, simply use ShapeableImageView
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
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.
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;
}
}
Another easy way is to use a CardView with the corner radius and an ImageView inside:
<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>
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:
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.
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.
Starting with the version 1.2.0-alpha03 of 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 in your themes.xml:
<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());
With jetpack compose you can apply a clip Modifier using a RoundedCornerShape:
Image(
painter = painterResource(R.drawable.xxxx),
contentDescription = "xxxx",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(64.dp)
.clip(RoundedCornerShape(8.dp))
)
In the v21 of the Support library there is now a solution to this: it's called RoundedBitmapDrawable.
It's basically just like a normal Drawable except you give it a corner radius for the clipping with:
setCornerRadius(float cornerRadius)
So, starting with Bitmap src and a target ImageView, it would look something like this:
RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(res, src);
dr.setCornerRadius(cornerRadius);
imageView.setImageDrawable(dr);
A quick xml solution -
<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.
With AndroidX, use <androidx.cardview.widget.CardView>
I have done by 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);
}
}
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:
Hope this would help you.
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.
#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!
Rounded image Using ImageLoader here
Create 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 Picasso Library from Square.
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
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:
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.
Hope it helps somebody, too.
Edit as per CQM request the relative layout example:
<?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>
It can be done with a ShapeableImageView using a ShapeAppearanceOverlay:
<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"/>
Where style ShapeAppearanceOverlay.Avatar resides in res/values/styles.xml:
<style name="ShapeAppearanceOverlay.Avatar" parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">50%</item>
</style>
This just need equal layout_height and layout_width set, else with will be a pill an no circle.
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);
}
}
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);
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:
Try the Material Components Library and use the ShapeableImageView.
Somethig like this :
Java :
imageView=new ShapeableImageView(context);
imageView.setShapeAppearanceModel(
imageView.getShapeAppearanceModel()
.toBuilder()
.setAllCornerSizes(20)
.build());
Kotlin :
val imageView = ShapeableImageView(context)
imageView.setShapeAppearanceModel(
imageView.getShapeAppearanceModel()
.toBuilder()
.setAllCornerSizes(20f)
.build())
Here is a simple example overriding imageView, you can then also use it in layout designer to preview.
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);
}
}
This is for fast solution. Radius is used on all corners and is based of percentage of bitmap width.
I just overrided setImageDrawable and used support v4 method for rounded bitmap drawable.
Usage:
<com.example.widgets.RoundedImageView
android:layout_width="39dp"
android:layout_height="39dp"
android:src="#drawable/your_drawable" />
Preview with imageView and custom imageView:
Kotlin
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)
To make ImageView Circular we can change cornerRadius with:
rounded.isCircular = true
Apply a shape to your imageView as below:
<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>
it may be helpful to you friend.
You should extend ImageView and draw your own rounded rectangle.
If you want a frame around the image you could also superimpose the rounded frame on top of the image view in the layout.
[edit]Superimpose the frame on to op the original image, by using a FrameLayout for example. The first element of the FrameLayout will be the image you want to diplay rounded. Then add another ImageView with the frame. The second ImageView will be displayed on top of the original ImageView and thus Android will draw it's contents above the orignal ImageView.
Props to George Walters II above, I just took his answer and extended it a bit to support rounding individual corners differently. This could be optimized a bit further (some of the target rects overlap), but not a whole lot.
I know this thread is a bit old, but its one of the top results for queries on Google for how to round corners of ImageViews on Android.
/**
* 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;
}
Romain Guy is where it's at.
Minified version as follows.
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);
Why not do clipping in draw()?
Here is my solution:
Extend RelativeLayout with clipping
Put ImageView (or other views) into the layout:
Code:
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;
}
}
}
This pure xml solution was good enough in my case. http://www.techrepublic.com/article/pro-tip-round-corners-on-an-android-imageview-with-this-hack/
EDIT
Here's the answer in a nutshell:
In the /res/drawable folder, create a frame.xml file. In it, we define a simple rectangle with rounded corners and a transparent center.
<?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>
In your layout file you add a LinearLayout that contains a standard ImageView, as well as a nested FrameLayout. The FrameLayout uses padding and the custom drawable to give the illusion of rounded corners.
<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>
None of the methods provided in the answers worked for me. I found the following way works if your android version is 5.0 or above:
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);
}
No xml shapes to be defined, and the code above create corners only for top, which normal methods won't work. If you need 4 corners to be rounded, remove:
"+ curveRadius"
From the parameter for bottom in setRoundRect. You can further expand the shape to any others by specifying outlines that suit your needs. Check out the following link:
Android Developer Documentation.
Note, as with any measure in Android, you have to "convert" the size typically from DP. In the example above, say you want the radius to be 24
int curveRadius = 24;
For example you may be later adding a border in a drawable with the radius set as "24" and you wish it to match. Hence,
float desiredRadius = 24;
float radiusConverted = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
desiredRadius,
itemView.getContext().getResources().getDisplayMetrics());
and then
int curveRadius = radiusConverted;
The following creates a rounded rectangle layout object that draws a rounded rectangle around any child objects that are placed in it. It also demonstrates how to create views and layouts programmatically without using the layout xml files.
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);
}
}
The class for RoundedRectangle layout object is as defined here:
/**
* 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;
}
}
If you are using Glide Library this would be helpful:
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));
}
Thanks a lot to first answer. Here is modified version to convert a rectangular image into a square one (and rounded) and fill color is being passed as parameter.
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;
}
if your image is on internet the best way is using glide and RoundedBitmapDrawableFactory (from API 21 - but available in support library) like so:
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);
}
});
Answer for the question that is redirected here:
"How to create a circular ImageView in Android?"
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;
}

Categories

Resources