Circular ImageView on Xamarin - android

I am working on a Xamarin Android application, and I need to make a Circular ImageView.
How can this be achieved?

I use the RoundedImageView library. It's written in Java, but you can write a binding to it without much problems. Once you do, you can simply add this to your .axml:
<RoundedImageView
local:riv_corner_radius="15dp"
local:riv_oval="false"
android:scaleType="centerCrop"
android:layout_width="30dp"
android:layout_height="30dp" />
Edit for future readers: I wrote a port of the RoundedImageView for Xamarin.Android, based on the library linked on this post. The source code can be found here and the NuGet package here. A MvxRoundedImageView is also included for use with MvvmCross.

Refer link: https://github.com/jamesmontemagno/CircleImageView-Xamarin.Android/blob/master/CircleImageSample/Resources/layout/Main.axml?
<refractored.controls.CircleImageView
android:id="#+id/ImageProfile"
android:layout_width="80dp"
android:layout_height="80dp"
android:scaleType="fitCenter"
android:src="#drawable/app_icon"
android:layout_gravity="center_horizontal"/>
===========================================================================
Add reference of Refractored.controls.CircleImageView to your project from nuget package.

Xamarin component is Available for the same, you can check it here

public class CircleDrawable : Drawable
{
Bitmap bmp;
BitmapShader bmpShader;
Paint paint;
RectF oval;
public CircleDrawable (Bitmap bmp)
{
this.bmp = bmp;
this.bmpShader = new BitmapShader (bmp, Shader.TileMode.Clamp, Shader.TileMode.Clamp);
this.paint = new Paint () { AntiAlias = true };
this.paint.SetShader (bmpShader);
this.oval = new RectF ();
}
public override void Draw (Canvas canvas)
{
canvas.DrawOval (oval, paint);
}
protected override void OnBoundsChange (Rect bounds)
{
base.OnBoundsChange (bounds);
oval.Set (0, 0, bounds.Width (), bounds.Height ());
}
public override int IntrinsicWidth {
get {
return bmp.Width;
}
}
public override int IntrinsicHeight {
get {
return bmp.Height;
}
}
public override void SetAlpha (int alpha)
{
}
public override int Opacity {
get {
return (int)Format.Opaque;
}
}
public override void SetColorFilter (ColorFilter cf)
{
}
}
Source: https://github.com/xamarin/xamarin-store-app/blob/master/XamarinStore.Droid/Views/CircleDrawable.cs

Refer these links:
How to create a circular ImageView in Android?
How to make an ImageView with rounded corners?
The above code works for native android. You need to tweak the code to convert into c# syntax and adopt for xamarin android. For your convenience I have changed the code to c#.
public class ImageHelper
{
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
Bitmap output = Bitmap.CreateBitmap(bitmap.Width, bitmap.Height
, Android.Graphics.Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(output);
Color color = Color.DodgerBlue;
Paint paint = new Paint();
Rect rect = new Rect(0, 0, bitmap.Width, bitmap.Height);
RectF rectF = new RectF(rect);
float roundPx = pixels;
paint.AntiAlias = true;
canvas.DrawARGB(0, 0, 0, 0);
paint.Color = color;
canvas.DrawRoundRect(rectF, roundPx, roundPx, paint);
paint.SetXfermode(new PorterDuffXfermode(Android.Graphics.PorterDuff.Mode.SrcIn));
canvas.DrawBitmap(bitmap, rect, rect, paint);
return output;
}

Related

Android Mask bitmap on canvas gen a black space

I have a mask bitmap with a half is red color and ones is transparent like this
https://www.dropbox.com/s/931ixef6myzusi0/s_2.png
I want to use mask bitmap to draw content on canvas only visible in red area, code like this:
Paint paint = new Paint();
public void draw(Canvas canvas) {
// draw content here
...
//and mask bitmap here
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
canvas.drawBitmap(maskBitmap, 0, 0, paint);
}
The result as my expecting (content only visible in red area, BUT THE TRANSPARENT AREA BECOME BLACK IS PROBLEM!)
this image result :https://www.dropbox.com/s/mqj48992wllfkiq/s_2%20copy.png
Anyone help me???
Here is a solution which helped me to implement masking:
public void draw(Canvas canvas) {
Bitmap original = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.original_image);
Bitmap mask = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.mask_image);
//You can change original image here and draw anything you want to be masked on it.
Bitmap result = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888);
Canvas tempCanvas = new Canvas(result);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
tempCanvas.drawBitmap(original, 0, 0, null);
tempCanvas.drawBitmap(mask, 0, 0, paint);
paint.setXfermode(null);
//Draw result after performing masking
canvas.drawBitmap(result, 0, 0, new Paint());
}
The mask should be a white image with transparency.
It will work like this:
+ =
I encountered the same problem in my custom view and instead of decoding the bitmap from a resource, I had created the original bitmap and the masking bitmap from the scratch via canvas.draw*() methods (since both the original and mask are basic shapes). I was getting the blank opaque space instead of a transparent one. I fixed it by setting a hardware layer to my view.
View.setLayerType(LAYER_TYPE_HARDWARE, paint);
More info on why this is to be done here: https://stackoverflow.com/a/33483016/4747587
Same answer as #Sergey Pekar give but I have updated it in Kotlin.
fun ImageView.getMaskBitmap(imageUrl: String? = null, mContent: Int, mMaskedImage : Int) {
runOnBackground {
// if you have https image url then use below line
//val original: Bitmap = BitmapFactory.decodeStream(URL(imageUrl).openConnection().getInputStream())
// if you have png or jpg image then use below line
val original: Bitmap = BitmapFactory.decodeResource(resources, mContent)
val mask = BitmapFactory.decodeResource(resources, mMaskedImage) // mMaskedImage Your masking image
val result: Bitmap = Bitmap.createBitmap(mask.width, mask.height, Bitmap.Config.ARGB_8888, true)
val tempCanvas = Canvas(result)
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
tempCanvas.apply {
drawBitmap(original, 0f, 0f, null)
drawBitmap(mask, 0f, 0f, paint)
}
paint.xfermode = null
//Draw result after performing masking
runOnBackground(onMainThread = {
this.apply {
setImageBitmap(result)
scaleType = ImageView.ScaleType.FIT_CENTER
}
})
}
}
Github Demo
Bitmap finalMasking = stackMaskingProcess(imageBitmap, bitmapMasking);
private Bitmap stackMaskingProcess(Bitmap _originalBitmap, Bitmap _maskingBitmap) {
try {
if (_originalBitmap != null)
{
int intWidth = _originalBitmap.getWidth();
int intHeight = _originalBitmap.getHeight();
resultMaskBitmap = Bitmap.createBitmap(intWidth, intHeight, Bitmap.Config.ARGB_8888);
getMaskBitmap = Bitmap.createScaledBitmap(_maskingBitmap, intWidth, intHeight, true);
Canvas mCanvas = new Canvas(resultMaskBitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas.drawBitmap(_originalBitmap, 0, 0, null);
mCanvas.drawBitmap(getMaskBitmap, 0, 0, paint);
paint.setXfermode(null);
paint.setStyle(Paint.Style.STROKE);
}
} catch (OutOfMemoryError o) {
o.printStackTrace();
}
return resultMaskBitmap;
}
I like the approach from Er. Praful Parmar's answer but for me it did not quite work as expected. I had problems, because some scaling was going on without intention.
My Bitmaps had a different density than my device and this messed things up.
Also I wanted to reduce the creation of Objects, so I moved the Paint object to a constant for reuse.
So here is my utils method:
public static final//
Bitmap createWithMask(final Bitmap img, final Bitmap mask) {
final Bitmap result = Bitmap.createBitmap(img.getWidth(), img.getHeight(),
Bitmap.Config.ARGB_8888);
result.setDensity(originalBitmap.getDensity()); // to avoid scaling if density of 'img' is different form the default on your device
final Canvas canvas = new Canvas(result);
canvas.drawBitmap(img, 0, 0, null);
canvas.drawBitmap(mask, 0, 0, PAINT_FOR_MASK);
return result;
}//end-method
private static final Paint PAINT_FOR_MASK = createPaintForMask();
private static final//
Paint createPaintForMask() {
final Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
return paint;
}//end-method

Rounded corners with Picasso

Is there a reasonable way to do rounded corners with Picasso that
Doesn't significantly slow down drawing
Works with hardware layers
Doesn't create an extra bitmap for each image
Allows resizing the downloaded bitmap into the size of the destination imageview
Most of the picasso advice on rounded corners suggests that a transformation be used, but I haven't seen an example that doesn't create an extra bitmap as part of the transformation.
This seems to be because Picasso only uses bitmaps, while the tricks to do rounded corners use the fact that you can dynamically draw the rounded corners on reasonably efficiently (most solutions use something along the lines of http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/).
Doing this with Volley was a bit hacky but possible, by just changing the type of ImageView to something that took a custom drawable, which drew rounded corners. Since Picasso needs bitmaps (at least, there's only a bitmap -> bitmap transformation), this is out, since the conversion of the drawable to bitmap creates a bitmap in the process.
One solution would be to do the work to modify picasso in a branch on my own that added a bitmap -> drawable transform, but I'd imagine there's a better way to go about this.
I do not want to draw a 9-patch on top of a view to give the appearance of rounded corners.
This code works fine for me
Picasso.with(getApplicationContext())
.load(sp.getString("image_url", ""))
.transform(new RoundedTransformation(100, 0))
.fit()
.into(userProfileImg);
// here is the class for make
public class RoundedTransformation implements
com.squareup.picasso.Transformation {
private final int radius;
private final int margin; // dp
// radius is corner radii in dp
// margin is the board in dp
public RoundedTransformation(final int radius, final int margin) {
this.radius = radius;
this.margin = margin;
}
#Override
public Bitmap transform(final Bitmap source) {
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP));
Bitmap output = Bitmap.createBitmap(source.getWidth(),
source.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
canvas.drawRoundRect(new RectF(margin, margin, source.getWidth()
- margin, source.getHeight() - margin), radius, radius, paint);
if (source != output) {
source.recycle();
}
return output;
}
#Override
public String key() {
return "rounded";
}
}
I also needed something like this, but with a border. I've searched the internet and I've found one version (without rounded corners) that looked good, but the border was over the image and I didn't like that. So I made my own version with the border outside the image.
public class BitmapBorderTransformation implements Transformation {
private int mBorderSize;
private int mCornerRadius = 0;
private int mColor;
public BitmapBorderTransformation(int borderSize, int color) {
this.mBorderSize = borderSize;
this.mColor = color;
}
public BitmapBorderTransformation(int borderSize, int cornerRadius, int color) {
this.mBorderSize = borderSize;
this.mCornerRadius = cornerRadius;
this.mColor = color;
}
#Override
public Bitmap transform(Bitmap source) {
int width = source.getWidth();
int height = source.getHeight();
Bitmap image = Bitmap.createBitmap(width, height, source.getConfig());
Canvas canvas = new Canvas(image);
canvas.drawARGB(0, 0, 0, 0);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Rect rect = new Rect(0, 0, width, height);
if(this.mCornerRadius == 0) {
canvas.drawRect(rect, paint);
}
else {
canvas.drawRoundRect(new RectF(rect),
this.mCornerRadius, this.mCornerRadius, paint);
}
paint.setXfermode(new PorterDuffXfermode((PorterDuff.Mode.SRC_IN)));
canvas.drawBitmap(source, rect, rect, paint);
Bitmap output;
if(this.mBorderSize == 0) {
output = image;
}
else {
width = width + this.mBorderSize * 2;
height = height + this.mBorderSize * 2;
output = Bitmap.createBitmap(width, height, source.getConfig());
canvas.setBitmap(output);
canvas.drawARGB(0, 0, 0, 0);
rect = new Rect(0, 0, width, height);
paint.setXfermode(null);
paint.setColor(this.mColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(new RectF(rect), this.mCornerRadius, this.mCornerRadius, paint);
canvas.drawBitmap(image, this.mBorderSize, this.mBorderSize, null);
}
if(source != output){
source.recycle();
}
return output;
}
#Override
public String key() {
return "bitmapBorder(" +
"borderSize=" + this.mBorderSize + ", " +
"cornerRadius=" + this.mCornerRadius + ", " +
"color=" + this.mColor +")";
}
}
Here are some samples:
Border with rounded corners:
new BitmapBorderTransformation(3, 15, Color.WHITE);
http://postimg.org/image/68fz5md39/
Rounded corners without border:
new BitmapBorderTransformation(0, 15, Color.WHITE);
http://postimg.org/image/he4681rsv/
Also you can do border without rounded corners:
new BitmapBorderTransformation(3, Color.WHITE);
this will work for any image of any size--
1) first create an empty image container for different resolution
2) then on runtime get its height and width by this-------
BitmapFactory.Options dimensions = new BitmapFactory.Options();
dimensions.inJustDecodeBounds = true;
Bitmap mBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon, dimensions);
int height = dimensions.outHeight;
int width = dimensions.outWidth;
3)
Picasso.with(getActivity())
.load(url)
.error(R.drawable.image2)
.placeholder(R.drawable.ic_drawer)
.resize(width, height )
.transform(new ImageTrans_roundedcorner())
.into(imageView1);
4) now transformation class----
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.Rect;
import android.graphics.RectF;
import com.squareup.picasso.Transformation;
public class ImageTrans_roundedcorner implements Transformation{
private int mBorderSize=10;
private int mCornerRadius = 20;
private int mColor=Color.BLACK;
#Override
public Bitmap transform(Bitmap source) {
// TODO Auto-generated method stub
Bitmap output = Bitmap.createBitmap(source.getWidth(), source.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, source.getWidth(), source.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = mCornerRadius;
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(source, rect, rect, paint);
// draw border
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth((float) mBorderSize);
canvas.drawRoundRect(rectF, mCornerRadius, mCornerRadius, paint);
//-------------------
if(source != output) source.recycle();
return output;
}
#Override
public String key() {
// TODO Auto-generated method stub
return "grayscaleTransformation()";
}
}
EDIT: the answer I would suggest would be to wait for Picasso 2.3, or fork their github now, where you can actually get at a BitmapDrawable.
One approach I've found so far is that you can load images into a Target object, create a custom drawable from the bitmap that way, then set the drawable into the ImageView, where it'll draw without creating a new bitmap.
This approach sort of sucks for a few reasons though:
1) You have to manage Target objects. These are weak-referenced (thankfully), so you have to keep track of them yourself. Ick. Memory leaks ahoy.
2) When you get the callback, you had better check to make sure the state of the world is still relevant to the picture, which is part of what you want to avoid by using picasso.
In short, there are a few things that seem to prevent a better solution.
1) Picasso wraps bitmaps in PicassoDrawables. This means you you have to handle arbitrary drawables in your custom imageView (if you go that route), or special case for this class.
2) PicassoDrawable doesn't expose the source bitmap, so you have to convert the drawable to a bitmap (requires creating a new bitmap, afaict).
3) There's no bitmap -> drawable transform function (see #1 for why, most likely).
Would love to hear if there's something I'm missing, or someone has come up with a better solution. Right now my best plan is to either do the Target management proposed above, or fork the picasso repo, change PicassoDrawable to have a public accessor for the underlying bitmap, and do the conversion into a custom drawable that way in my imageView.

Bitmap in ImageView with rounded corners

I have an ImageView and I want to make it with rounded corners.
I use this:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#null"/>
<stroke android:width="1dp"
android:color="#ff000000"/>
<corners android:radius="62px"/>
</shape>
And set this code as background of my imageview.
It works, but the src image that I put on the ImageView is going out of the borders and doesn't adapt itself into the new shape.
How can I solve the problem?
try this one :
public class CustomImageView extends ImageView {
public static float radius = 18.0f;
public CustomImageView(Context context) {
super(context);
}
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
//float radius = 36.0f;
Path clipPath = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
clipPath.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
}
}
and
<your.pack.name.CustomImageView
android:id="#+id/selectIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="centerCrop" />
CustomImageView iconImage = (CustomImageView )findViewById(R.id.selectIcon);
iconImage.setImageBitmap(bitmap);
or,
ImageView iv= new CustomImageView(this);
iv.setImageResource(R.drawable.pic);
It's strange that nobody here has mentioned RoundedBitmapDrawable from Android Support Library v4. For me it is the simplest way to get rounded corners without borders. Here is example of usage:
RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(getResources(), bitmap);
final float roundPx = (float) bitmap.getWidth() * 0.06f;
roundedBitmapDrawable.setCornerRadius(roundPx);
Make one function which make rounded to your bitmap using canvas.
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;
}
for more info:> here
The accepted answer uses path clipping, but it doesn't support anti-aliasing. See Romain Guy's comments on his post. "path clipping does not support antialiasing and you get jagged edges."
http://www.curious-creature.com/2012/12/11/android-recipe-1-image-with-rounded-corners/
There is one good library(vinc3m1’s RoundedImageView) that supoorts rounded corners on ImageView, but it only supports the same radiuses on every corners. So I made one that you can set different radiuses on each corners.
It doesn't rely on path clipping, nor redrawing. It only draws one time with canvas.drawPath() method. So I finally got result that I wanted like below.
See : https://github.com/pungrue26/SelectableRoundedImageView
For me, the below method does the magic. :)
This method accepts a bitmap object and returns it back with rounded corners. roundPx is the number of rounded pixels you want:
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
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 = 12;
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;
}
...or you could use this library instead of ImageView without any further coding.
If you need make Bitmap with different corner radii and I recommend follow code:
private static Bitmap createRoundedRectBitmap(#NonNull Bitmap bitmap,
float topLeftCorner, float topRightCorner,
float bottomRightCorner, float bottomLeftCorner) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = Color.WHITE;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
Path path = new Path();
float[] radii = new float[]{
topLeftCorner, bottomLeftCorner,
topRightCorner, topRightCorner,
bottomRightCorner, bottomRightCorner,
bottomLeftCorner, bottomLeftCorner
};
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
path.addRoundRect(rectF, radii, Path.Direction.CW);
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
If you need border also then:
1. You can use a rounded box image with a transparent body and white from outside. For Example:
and use this with target image like below:
<FrameLayout
android:layout_width="100px"
android:layout_height="100px" >
<ImageView
android:id="#+id/targetImage"
android:layout_width="100px"
android:layout_height="100px"
android:src="#drawable/app_icon"
android:layout_gravity="center" />
<ImageView
android:id="#+id/boxImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="#drawable/box" />
Adding CardView as parent layout of ImageView also be a good solution.
It can be done with background drawable, like explain in many posts including this one, but it also needs to set clipping.
Here a full example:
The code:
AppCompatImageView iconView = findViewById(R.id.thumbnail);
iconView.setClipToOutline(true);
The layout:
<android.support.v7.widget.AppCompatImageView
android:id="#+id/thumbnail"
android:layout_width="80dp"
android:layout_height="80dp"
android:contentDescription="#string/thumbnail"
android:scaleType="centerInside"
android:background="#drawable/round_view" <!--here set the drawable as background -->
tools:src="#mipmap/ic_user" />
The drawable:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
</shape>
/**
* Creates new circular bitmap based on original one.
* #param newCornerRadius is optional
*/
fun Bitmap.toCircular(context: Context, newCornerRadius: Float? = null): RoundedBitmapDrawable {
return RoundedBitmapDrawableFactory.create(context.resources, this).apply {
isCircular = true
newCornerRadius?.let {
cornerRadius = it
}
}
}
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 defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap rounder = Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvasRound = new Canvas(rounder);
Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xferPaint.setColor(Color.BLACK);
final int rx = this.getWidth(); //our x radius
final int ry = this.getHeight(); //our y radius
canvasRound.drawRoundRect(new RectF(0,0,rx,ry), rx, ry, xferPaint);
xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(rounder, 0, 0, xferPaint);
}
}
Kotlin version
fun Bitmap.roundCorner(pixels: Int): Bitmap {
val output: Bitmap = Bitmap.createBitmap(
width, height, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(output)
val color = -0xbdbdbe
val paint = Paint()
val rect = Rect(0, 0, width, height)
val rectF = RectF(rect)
val roundPx = pixels.toFloat()
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = color
canvas.drawRoundRect(rectF, roundPx, roundPx, paint)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(this, rect, rect, paint)
return output
}
call by:
sourceBitmap.roundCorner(60)
The method to make rounded corners for imageview in android is not rocket science guys! just use a png with required curves with the same color as your background and set the overlay to FITXY.!
public void drawRoundImage(boolean isEditPicEnable){
if(originalImageBitmap != null){
setBackgroundResource(R.drawable.ic_account_user_outer_circle_blue);
if (isEditPicEnable) {
setBackgroundResource(R.drawable.ic_account_user_outer_circle_white);
Bitmap mask = BitmapFactory.decodeResource(getResources(), R.drawable.ic_account_white_mask);
Bitmap mask1 = BitmapFactory.decodeResource(getResources(), R.drawable.ic_account_pencil_bg);
originalImageBitmap = Bitmap.createScaledBitmap(originalImageBitmap, mask.getWidth(), mask.getHeight(), true);
Bitmap result = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Bitmap.Config.ARGB_8888);
Canvas mCanvas = new Canvas(result);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas.drawBitmap(originalImageBitmap, 0, 0, null);
mCanvas.drawBitmap(mask, 0, 0, paint);
mCanvas.drawBitmap(mask1, 0, 0, null);
Bitmap mask2 = BitmapFactory.decodeResource(getResources(), R.drawable.ic_account_pencil);
mCanvas.drawBitmap(mask2, 0, 0, null);
setImageBitmap(result);
setScaleType(ScaleType.FIT_XY);
} else {
Bitmap mask = BitmapFactory.decodeResource(getResources(),R.drawable.ic_account_white_mask);
originalImageBitmap = Bitmap.createScaledBitmap(originalImageBitmap, mask.getWidth(),mask.getHeight(), true);
Bitmap result = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(),Bitmap.Config.ARGB_8888);
Canvas mCanvas = new Canvas(result);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas.drawBitmap(originalImageBitmap, 0, 0, null);
mCanvas.drawBitmap(mask, 0, 0, paint);
paint.setXfermode(null);
setImageBitmap(result);
setScaleType(ScaleType.FIT_XY);
}
}else{
setBackgroundResource(R.drawable.ic_account_user_outer_circle_blue);
setImageResource(R.drawable.my_ac_default_profile_pic);
}
}

Antialiased rounded corners on Android ImageView [duplicate]

This question already has answers here:
How to make an ImageView with rounded corners?
(58 answers)
Closed 9 years ago.
I am new to android dev, and I have been trying for a few hours now to add nice and smooth rounded corners to an ImageView, without success.
First thing I tried is simply to round corners of my images directly, but this implies changing the bitmap, and since I need to keep the raw ones, and those are pretty big, this is not really memory friendly. This would also cause other difficulties since my ImageView is fluid.
Second thing I tried to use is the clipPath method after subclassing my view. This works, but corners are aliased. I then tried adding a PaintFlagsDrawFilter to implement the aliasing, but this didn't worked. I'm using monodroid, and I was wondering this was supposed to work in Java.
Here is my code (C#):
public class MyImageView : ImageView
{
private float[] roundedCorner;
/**
* Contains the rounded corners for the view.
* You can define one, four or height values.
* This behaves as the css border-radius property
*
* #see http://developer.android.com/reference/android/graphics/Path.html#addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction)
*/
public float[] RoundedCorners{
get{
return roundedCorner;
}
set{
float[] finalValue = new float[8];
int i=0;
if(value.Length == 1){
for(i=0; i<8;i++){
finalValue[i] = value[0];
}
}else if(value.Length == 4){
for(i=0; i<4;i++){
finalValue[2*i] = value[i];
finalValue[2*i+1] = value[i];
}
}
roundedCorner = finalValue;
}
}
public SquareImageView (Context context) :
base (context)
{
Initialize ();
}
public SquareImageView (Context context, IAttributeSet attrs) :
base (context, attrs)
{
Initialize ();
}
private void Initialize ()
{
RoundedCorners = new float[]{0,0,0,0};
}
public override void Draw (Android.Graphics.Canvas canvas)
{
Path path = new Path();
path.AddRoundRect(new RectF(0,0, Width,Height),RoundedCorners, Path.Direction.Cw);
canvas.ClipPath(path);
base.Draw (canvas);
}
/**
* try to add antialiasing.
*/
protected override void DispatchDraw (Canvas canvas)
{
canvas.DrawFilter = new PaintFlagsDrawFilter((PaintFlags)1, PaintFlags.AntiAlias);
base.DispatchDraw (canvas);
}
}
Thanks for your help!
I've created a RoundedImageView based off Romain Guy's example code that wraps this logic into an ImageView that you should be able to just use. It supports borders and antialiasing out of the box.
It's more efficient than other rounded corner examples because it doesn't create another copy of the bitmap, nor does it use clipPath which draws twice to the canvas.
use below code
public Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels)
{
Bitmap output = null;
if(bitmap != null)
{
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;
}
and call this method like
imageView.setImageBitmap(getRoundedCornerBitmap(bitmap, 10));

Android - Touch to erase portions of foreground ImageView to expose background View

So I've been struggling with this for a better part of a day. Suppose I have a custom ImageView that I want to overlay over a background View (both within a RelativeLayout), which when touched, it erases portions of the View's source bitmap like an erase tool in MS Paint, exposing the View below it. I've checked pretty much all of the threads (like this one) and they suggest to use PorterDuff SRC Mode in the Paint object as well as creating a Canvas out out the ARGB_8888 shadow copy of the source bitmap to apply the masking.
Also, I can't set the source of the overlay ahead of time since I have to download it over the network so that the ImageView's scale type takes care of the scaling for me.
Every time I override onDraw, when I apply the erase on the IV's Bitmap, it unveils a black background instead of the view below it, even though I set the background to transparent. So I'm at my last rope as to what to do in order to unveil the background view.
Here's what I have so far:
view constructor:
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
paint.setAntiAlias(true);
overrode setImageBitmap to set my canvas from my re-configed source bitmap:
public void setImageBitmap(Bitmap bitmap){
super.setImageBitmap(bitmap);
Drawable bd = getDrawable();
if(bd == null){
return;
}
Bitmap fullSizeBitmap = ((BitmapDrawable) bd).getBitmap();
overlay = fullSizeBitmap.copy(Config.ARGB_8888, true);
c2 = new Canvas(overlay);
}
onDraw method:
protected void onDraw(Canvas canvas) {
/*
* Override paint call by re-drawing the view's Bitmap first, then overlaying our path on top of it
*/
Drawable bd = getDrawable();
if(bd == null){
return;
}
Bitmap fullSizeBitmap = ((BitmapDrawable) bd).getBitmap();
if(fullSizeBitmap != null && c2 != null){
canvas.drawColor(Color.TRANSPARENT);
c2.drawBitmap(fullSizeBitmap, 0, 0, null);
c2.drawPath(path, paint);
canvas.drawBitmap(overlay, 0, 0, null);
}
}
I know this is a really old question but here is what I did to fix a similar problem I had. Maybe it helps someone in the future.
From API level 11 and up you have to specify this piece of code for your ImageView to unveil the image in the back and not a black area.
if (Build.VERSION.SDK_INT >= 11) {
imageview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
This helped me displaying the back image successfully
Can you try this solution it will help you with the erasing images in android on touch .. Or download a demo example
public class MainActivity extends Activity {
Bitmap bp;
Canvas bitmapCanvas;
DrawView drawImg;
LinearLayout ln1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ln1 = (LinearLayout) findViewById(R.id.ln1);
drawImg = new DrawView(this);
ln1.addView(drawImg);
}
public class DrawView extends View implements View.OnTouchListener {
private int x = 0;
private int y = 0;
Bitmap bitmap;
Path circlePath;
Paint circlePaint;
private final Paint paint = new Paint();
private final Paint eraserPaint = new Paint();
public DrawView(Context context){
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
// Set background
this.setBackgroundColor(Color.CYAN);
bp = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
// Set bitmap
bitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas();
bitmapCanvas.setBitmap(bitmap);
bitmapCanvas.drawColor(Color.TRANSPARENT);
bitmapCanvas.drawBitmap(bp, 0, 0, null);
circlePath = new Path();
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
// Set eraser paint properties
eraserPaint.setAlpha(0);
eraserPaint.setStrokeJoin(Paint.Join.ROUND);
eraserPaint.setStrokeCap(Paint.Cap.ROUND);
eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
eraserPaint.setAntiAlias(true);
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, paint);
bitmapCanvas.drawCircle(x, y, 30, eraserPaint);
canvas.drawPath(circlePath, circlePaint);
}
public boolean onTouch(View view, MotionEvent event) {
x = (int) event.getX();
y = (int) event.getY();
bitmapCanvas.drawCircle(x, y, 30, eraserPaint);
circlePath.reset();
circlePath.addCircle(x, y, 30, Path.Direction.CW);
int ac=event.getAction();
switch(ac){
case MotionEvent.ACTION_UP:
Toast.makeText(MainActivity.this, String.valueOf(x), Toast.LENGTH_SHORT).show();
circlePath.reset();
break;
}
invalidate();
return true;
}
}
}

Categories

Resources