I need to get circle images from rectangular/square images taken from network. In my application I get images with Volley's NetworkImageView. I found that fantastic library https://github.com/hdodenhof/CircleImageView but I don't understand how I can use it with NetworkImageView.
Can someone help me?
Check this Class
public class CirculaireNetworkImageView extends NetworkImageView {
private int borderWidth;
private int canvasSize;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
public CirculaireNetworkImageView(final Context context) {
this(context, null);
}
public CirculaireNetworkImageView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.actionButtonStyle);
}
public CirculaireNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
paintBorder.setAntiAlias(true);
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.requestLayout();
this.invalidate();
}
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
public void addShadow() {
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
#SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas) {
// load the bitmap
image = drawableToBitmap(getDrawable());
// init shader
if (image != null) {
canvasSize = canvas.getWidth();
if(canvas.getHeight()<canvasSize)
canvasSize = canvas.getHeight();
BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvasSize, canvasSize, false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
int circleCenter = (canvasSize - (borderWidth * 2)) / 2;
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// The parent has determined an exact size for the child.
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result;
}
private int measureHeight(int measureSpecHeight) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = canvasSize;
}
return (result + 2);
}
public Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
} else if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
Check the source code of the NetworkImageView here. Modify it to extend your "CircleImageView" instead of the normal ImageView and you are done.
Related
I'm writing a custom Circular ImageView in Android. I need to set a Drawable overlay on top of it, so I chose to write a custom CircularImageView that holds the picture itself + the drawable.
Actually I have 2 problems:
The image is drawn top-left, I need it to be drawn on the center of the View
I need my crown to be bigger (drawable) but I don't know how to resize it.
Some imgs to clarify:
What I'd like to achieve:
What I have now:(please, disconsider the black frame border, it's just to clarify the wrong image "gravity")
My view code:
public class CrownCircularImageView extends ImageView {
private Drawable crown;
private int canvasSize;
private int crownWidth;
private int crownHeight;
// Object used to draw
private Bitmap image;
private Drawable drawable;
private Paint paint;
private Paint crownPaint;
public CrownCircularImageView(Context context) {
this(context, null, 0);
}
public CrownCircularImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CrownCircularImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
crownPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.crown = ContextCompat.getDrawable(context, R.drawable.ic_crown);
}
private void loadBitmap() {
if (this.drawable == getDrawable())
return;
this.drawable = getDrawable();
this.image = drawableToBitmap(this.drawable);
updateShader();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasSize = w - crownWidth;
if (h < canvasSize)
canvasSize = h - crownHeight;
if (image != null)
updateShader();
}
private void updateShader() {
if (image == null)
return;
// Crop Center Image
image = cropBitmap(image);
// Create Shader
BitmapShader shader = new BitmapShader(image, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// Center Image in Shader
Matrix matrix = new Matrix();
matrix.setScale((float) canvasSize / (float) image.getWidth(), (float) canvasSize / (float) image.getHeight());
shader.setLocalMatrix(matrix);
// Set Shader in Paint
paint.setShader(shader);
}
private Bitmap cropBitmap(Bitmap bitmap) {
Bitmap bmp;
if (bitmap.getWidth() >= bitmap.getHeight()) {
bmp = Bitmap.createBitmap(
bitmap,
bitmap.getWidth() / 2 - bitmap.getHeight() / 2,
0,
bitmap.getHeight(),
bitmap.getHeight());
} else {
bmp = Bitmap.createBitmap(
bitmap,
0,
bitmap.getHeight() / 2 - bitmap.getWidth() / 2,
bitmap.getWidth(),
bitmap.getWidth());
}
return bmp;
}
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
} else if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
int intrinsicWidth = drawable.getIntrinsicWidth();
int intrinsicHeight = drawable.getIntrinsicHeight();
if (!(intrinsicWidth > 0 && intrinsicHeight > 0))
return null;
try {
// Create Bitmap object out of the drawable
Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (OutOfMemoryError e) {
// Simply return null of failed bitmap creations
Log.e(getClass().toString(), "Encountered OutOfMemoryError while generating bitmap!");
return null;
}
}
#Override
public void onDraw(Canvas canvas) {
// Load the bitmap
loadBitmap();
// Check if image isn't null
if (image == null)
return;
if (!isInEditMode()) {
canvasSize = canvas.getWidth();
if (canvas.getHeight() < canvasSize) {
canvasSize = canvas.getHeight();
}
}
int circleCenter = (canvasSize - crownHeight) / 2;
int cx = (canvasSize - crownWidth) / 2;
int cy = (canvasSize - crownHeight) / 2;
Bitmap crownBmp = drawableToBitmap(crown);
int crownX = cx;
int crownY = cy;
canvas.drawCircle(cx, cy, circleCenter, paint);
canvas.drawBitmap(crownBmp, crownX, crownY, crownPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
crownWidth = crown.getIntrinsicWidth();
crownHeight = crown.getIntrinsicHeight();
setMeasuredDimension(width, height);
}
#Override
public ScaleType getScaleType() {
return ScaleType.CENTER_CROP;
}
private int measureWidth(int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// The parent has determined an exact size for the child.
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result + crown.getIntrinsicWidth();
}
private int measureHeight(int measureSpecHeight) {
int result;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = canvasSize;
}
return (result + 2 + crown.getIntrinsicHeight());
}
}
You can create a new bitmap to draw the old one on a transparent background with a circle mask, and then draw the crown on it. This example also allows to add a padding around the image.
You will want to tweak the values of CIRCLE_PADDING and RESIZE_CROWN_FACTOR to fulfill your needs.
public class CrownImageView extends ImageView {
private static final int CIRCLE_PADDING = 25;
private static final float RESIZE_CROWN_FACTOR = 1.5f;
private Bitmap rounded;
private Bitmap resizedCrown;
public CrownImageView(final Context context) {
super(context);
}
public CrownImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public CrownImageView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null || getWidth() == 0 || getHeight() == 0) {
return;
}
if (resizedCrown == null) {
loadCrown();
}
loadImage(drawable);
canvas.drawBitmap(rounded, 0, 0, null);
canvas.drawBitmap(resizedCrown, canvas.getWidth() - resizedCrown.getWidth(), 0, null);
}
private void loadImage(Drawable drawable) {
Bitmap bmp = bitmapFromDrawable(drawable);
final Rect rect = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
rounded = Bitmap.createBitmap(bmp.getWidth(),
bmp.getHeight(), Bitmap.Config.ARGB_8888);
Canvas newCanvas = new Canvas(rounded);
newCanvas.drawARGB(0, 0, 0, 0);
float centerX = getWidth() / 2;
float centerY = getHeight() / 2;
float radius = Math.min(getWidth(), getHeight()) / 2 - CIRCLE_PADDING;
newCanvas.drawCircle(centerX, centerY, radius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
newCanvas.drawBitmap(bmp, rect, rect, paint);
}
private void loadCrown() {
Bitmap crown = BitmapFactory.decodeResource(getResources(), R.drawable.crown);
resizedCrown = Bitmap.createScaledBitmap(crown,
(int) (crown.getWidth() * RESIZE_CROWN_FACTOR),
(int) (crown.getHeight() * RESIZE_CROWN_FACTOR),
true);
}
private Bitmap bitmapFromDrawable(Drawable drawable) {
Bitmap bmp;
if (drawable instanceof BitmapDrawable) {
bmp = ((BitmapDrawable) drawable).getBitmap();
} else {
bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas bmpCanvas = new Canvas(bmp);
drawable.setBounds(0, 0, bmpCanvas.getWidth(), bmpCanvas.getHeight());
drawable.draw(bmpCanvas);
}
return bmp;
}
}
Update: You can use it with Glide like this
final CrownImageView imageView = (CrownImageView) findViewById(R.id.fragment_kids_row_img_kids);
Glide.with(this).load(yourimageurl).into(imageView);
The image is drawn top-left, I need it to be drawn on the center of the View
Yes, that is because of parameters to .drawCircle
canvas.drawCircle(cx, cy, circleCenter, paint);
You are not calculating them for your image. This should be something like
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
float bitmapRadius = Math.min(image.getWidth(), image.getHeight()) / 2f;
canvas.drawCircle(centerX, centerY, bitmapRadius, paint);
But I think it is better to save this values and recalculate them when size changes.
I need my crown to be bigger (drawable) but I don't know how to resize it.
You specify size of bitmap yourself - make it a bit bigger by specifying another size.
Bitmap bitmap = Bitmap.createBitmap(
intrinsicWidth + scale,
intrinsicHeight + scale,
Bitmap.Config.ARGB_8888);
I've modified your code: http://pastebin.com/0h02Tqh1
I have an Cirle imageview. I am setting the image to the ImageView from the camera and gallery. The problem is that when I set the image from the camera, the image looks too streched inside the circle image view.
Iam Resizing the image in order to avoid any memory leaks.
here is what i do:
CircleImageView.cs
public class CircleImageView : ImageView
{
private int borderWidth;
private int canvasSize;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
public CircleImageView(Context context)
: this(context, null)
{
}
public CircleImageView(Context context, IAttributeSet attrs)
: this(context, attrs, Resource.Attribute.circularImageViewStyle)
{
}
public CircleImageView(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
// init paint
paint = new Paint();
paint.AntiAlias = true;
paintBorder = new Paint();
paintBorder.AntiAlias = true;
// load the styled attributes and set their properties
TypedArray attributes = context.ObtainStyledAttributes(attrs, Resource.Styleable.CircularImageView, defStyle, 0);
if (attributes.GetBoolean(Resource.Styleable.CircularImageView_border, true))
{
int defaultBorderSize = (int)(4 * context.Resources.DisplayMetrics.Density+ 0.5f);
BorderWidth = attributes.GetDimensionPixelOffset(Resource.Styleable.CircularImageView_border_width, defaultBorderSize);
BorderColor = attributes.GetColor(Resource.Styleable.CircularImageView_border_color, Color.White);
}
if (attributes.GetBoolean(Resource.Styleable.CircularImageView_shadow, false))
{
addShadow();
}
}
public void addShadow()
{
SetLayerType(LayerType.Software, paintBorder);
paintBorder.SetShadowLayer(4.0f, 2.0f, 2.0f, Color.ParseColor("#82C341"));
}
public virtual int BorderWidth
{
set
{
this.borderWidth = 10;
this.RequestLayout();
this.Invalidate();
}
}
public virtual int BorderColor
{
set
{
if (paintBorder != null)
{
paintBorder.Color = Color.Gray;
}
this.Invalidate();
}
}
protected override void OnDraw(Canvas canvas)
{
// load the bitmap
image = drawableToBitmap(Drawable);
// init shader
if (image != null)
{
canvasSize = canvas.Width;
if (canvas.Height < canvasSize)
{
canvasSize = canvas.Height;
}
BitmapShader shader = new BitmapShader(Bitmap.CreateScaledBitmap(image, canvasSize, canvasSize, false), Shader.TileMode.Clamp, Shader.TileMode.Clamp);
paint.SetShader(shader);
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
int circleCenter = (canvasSize - (borderWidth * 2)) / 2;
canvas.DrawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) + borderWidth - 4.0f, paintBorder);
canvas.DrawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) - 4.0f, paint);
}
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
SetMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec)
{
int result = 0;
var specMode = MeasureSpec.GetMode(measureSpec);
var specSize = MeasureSpec.GetSize(measureSpec);
if (specMode == MeasureSpecMode.Exactly)
{
// The parent has determined an exact size for the child.
result = specSize;
}
else if (specMode == MeasureSpecMode.AtMost)
{
// The child can be as large as it wants up to the specified size.
result = specSize;
}
else
{
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result;
}
private int measureHeight(int measureSpecHeight)
{
int result = 0;
var specMode = MeasureSpec.GetMode(measureSpecHeight);
int specSize = MeasureSpec.GetSize(measureSpecHeight);
if (specMode == MeasureSpecMode.Exactly)
{
// We were told how big to be
result = specSize;
}
else if (specMode == MeasureSpecMode.AtMost)
{
// The child can be as large as it wants up to the specified size.
result = specSize;
}
else
{
// Measure the text (beware: ascent is a negative number)
result = canvasSize;
}
return (result + 2);
}
public virtual Bitmap drawableToBitmap(Drawable drawable)
{
if (drawable == null)
{
return null;
}
else if (drawable is BitmapDrawable)
{
return ((BitmapDrawable)drawable).Bitmap;
}
Bitmap bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth, drawable.IntrinsicHeight, Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(bitmap);
drawable.SetBounds(0, 0, canvas.Width, canvas.Height);
drawable.Draw(canvas);
return bitmap;
}
}
BitmapHelper.cs
public static Bitmap LoadAndResizeBitmap(this string fileName, int width, int height)
{
// First we get the the dimensions of the file on disk
BitmapFactory.Options options = new BitmapFactory.Options { InJustDecodeBounds = true };
BitmapFactory.DecodeFile(fileName, options);
// Next we calculate the ratio that we need to resize the image by
// in order to fit the requested dimensions.
int outHeight = options.OutHeight;
int outWidth = options.OutWidth;
int inSampleSize = 1;
if (outHeight > height || outWidth > width)
{
inSampleSize = outWidth > outHeight
? outHeight / height
: outWidth / width;
}
// Now we will load the image and have BitmapFactory resize it for us.
options.InSampleSize = inSampleSize;
options.InJustDecodeBounds = false;
Bitmap resizedBitmap = BitmapFactory.DecodeFile(fileName, options);
return resizedBitmap;
}
mylayout.xml
<Utilities.CircleImageView
android:layout_width="180dp"
android:layout_height="180dp"
android:id="#+id/imgProfileCircleImage"
android:src="#drawable/rapidicon"
custom:border="true"
custom:border_color="#d5d5d5"
custom:border_width="4dp"
custom:shadow="true"
android:layout_gravity="center"
android:minHeight="80dp"
android:minWidth="80dp" />
MainActivity
int imgheight = Resources.DisplayMetrics.HeightPixels;
int circleImgWidth = imgProfileCircleImage.Height;
AppHelper._bitmap = AppHelper._file.Path.LoadAndResizeBitmap(circleImgWidth, imgheight);
How do I set the image so that it looks perfectly fit to the imageview?
Try using Picasso or Glide to solve this issue easily
http://square.github.io/picasso/
I am working on android application in which i am using Bitmap, but the problem is that sometimes it shows me an error of out of memory and my application get crashed. I am using bitmaps along with BitmapShadder, my code is given below where my application shows this error.
public class CircularImageView extends ImageView {
private int borderWidth = 0;
private int viewWidth;
private int viewHeight;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
private BitmapShader shader;
public CircularImageView(Context context) {
super(context);
setup();
}
public CircularImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setup();
}
private void setup() {
// init paint
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
setBorderColor(Color.WHITE);
paintBorder.setAntiAlias(true);
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
// paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.invalidate();
}
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
private void loadBitmap() {
BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
if (bitmapDrawable != null)
image = bitmapDrawable.getBitmap();
}
// #SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas) {
// load the bitmap
loadBitmap();
// init shader
if (image != null) {
// Out Of Memory Error Comes Here....
shader = new BitmapShader(Bitmap.createScaledBitmap(image,canvas.getWidth(), canvas.getHeight(), false),Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
int circleCenter = viewWidth / 2;
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
canvas.drawCircle(circleCenter + borderWidth, circleCenter
+ borderWidth, circleCenter + borderWidth - 4.0f,
paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter
+ borderWidth, circleCenter - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
viewWidth = width - (borderWidth * 2);
viewHeight = height - (borderWidth * 2);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = viewWidth;
}
return result;
}
private int measureHeight(int measureSpecHeight, int measureSpecWidth) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = viewHeight;
}
return (result + 2);
}
}
Try this in your manifest application tag.
android:largeHeap="true"
I am trying to use the support lib v4's RoundedBitmapDrawable in order to display Rounded bitmaps loaded asynchronously in ImageViews, either circled or rounded rectangles.
However, it looks like RoundedBitmapDrawable does not mesh very well with LayerDrawable :
If I try something like :
if (previousDrawable != null) {
final Drawable[] layers = new Drawable[2];
layers[0] = previousDrawable;
layers[1] = roundedDrawable;
TransitionDrawable drawable = new TransitionDrawable(layers);
view.setImageDrawable(drawable);
drawable.startTransition(3000);
} else {
view.setImageDrawable(roundedDrawable);
}
The TransitionDrawable launches but it does not respect the RoundedBitmapDrawable is not correctly displayed : its dimensions seems to shift somehow, if I set it to be a circle with :
RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory
.create(getResources(), bitmap);
roundedDrawable.setCornerRadius(bitmap.getHeight() / 2);
roundedDrawable.setAntiAlias(true);
It is displayed correctly if I use ImageView.setImageDrawable(), but it results in a rounded rectangle if a TransitionDrawable displays it.
Does anybody has any idea why this display problem happen ?
Set
roundedDrawable.setCircular(true);
then it works fine
Use Universal Image loader to fix your issue
https://github.com/nostra13/Android-Universal-Image-Loader
This is my solution to create a rounded image:
package com.campusapp;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class CircularImageView extends ImageView {
private int borderWidth;
private int canvasSize;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
public CircularImageView(final Context context) {
this(context, null);
}
public CircularImageView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.circularImageViewStyle);
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// init paint
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
paintBorder.setAntiAlias(true);
// load the styled attributes and set their properties
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyle, 0);
if(attributes.getBoolean(R.styleable.CircularImageView_border, true))
{
int defaultBorderSize = (int) (4 * getContext().getResources().getDisplayMetrics().density + 0.5f);
setBorderWidth(attributes.getDimensionPixelOffset(R.styleable.CircularImageView_border_width, defaultBorderSize));
setBorderColor(attributes.getColor(R.styleable.CircularImageView_border_color, Color.WHITE));
}
if(attributes.getBoolean(R.styleable.CircularImageView_shadow, false))
addShadow();
}
public void setBorderWidth(int borderWidth)
{
this.borderWidth = borderWidth;
this.requestLayout();
this.invalidate();
}
public void setBorderColor(int borderColor)
{
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
public void addShadow()
{
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
#Override
public void onDraw(Canvas canvas)
{
// load the bitmap
image = drawableToBitmap(getDrawable());
// init shader
if (image != null)
{
canvasSize = canvas.getWidth();
if(canvas.getHeight()<canvasSize)
canvasSize = canvas.getHeight();
BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvasSize, canvasSize, false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
int circleCenter = (canvasSize - (borderWidth * 2)) / 2;
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY)
{
// The parent has determined an exact size for the child.
result = specSize;
}
else if (specMode == MeasureSpec.AT_MOST)
{
// The child can be as large as it wants up to the specified size.
result = specSize;
}
else
{
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result;
}
private int measureHeight(int measureSpecHeight)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY)
{
// We were told how big to be
result = specSize;
}
else if (specMode == MeasureSpec.AT_MOST)
{
// The child can be as large as it wants up to the specified size.
result = specSize;
}
else
{
// Measure the text (beware: ascent is a negative number)
result = canvasSize;
}
return (result + 2);
}
public Bitmap drawableToBitmap(Drawable drawable)
{
if (drawable == null)
{
return null;
}
else if (drawable instanceof BitmapDrawable)
{
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
After creating the class, replace your ImageView with the code below:
<com.yourpkg.CircularImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/your_image"
app:border_color="#EEEEEE"
app:border_width="4dp"
app:shadow="true" />
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, 0, w/2, h/2, paint);
}
if (squareTR ){
canvas.drawRect(w/2, 0, w, h/2, paint);
}
if (squareBL ){
canvas.drawRect(0, h/2, w/2, h, paint);
}
if (squareBR ){
canvas.drawRect(w/2, h/2, w, h, paint);
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(input, 0,0, paint);
return output;
}
or you can see this also
I am using circularimageView to display the picture of a person. Here's the class.
public class CircularImageView extends ImageView {
private int borderWidth = 4;
private int viewWidth;
private int viewHeight;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
private BitmapShader shader;
public CircularImageView(Context context) {
super(context);
setup();
}
public CircularImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setup();
}
private void setup() {
// init paint
paint = new Paint();
paintBorder = new Paint();
paint.setAntiAlias(true);
setBorderColor(Color.WHITE);
paintBorder.setAntiAlias(true);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
}
else
{
}
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.invalidate();
}
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
private void loadBitmap() {
BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
if (bitmapDrawable != null)
image = bitmapDrawable.getBitmap();
}
#SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas) {
// load the bitmap
loadBitmap();
// init shader
if (image != null) {
shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
int circleCenter = viewWidth / 2;
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
viewWidth = width - (borderWidth * 2);
viewHeight = height - (borderWidth * 2);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = viewWidth;
}
return result;
}
private int measureHeight(int measureSpecHeight, int measureSpecWidth) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = viewHeight;
}
return (result + 2);
}
}
It works fine in anything > API 10 but in other cases the image gets stretched out and only the top left part of the image is visible and is pixelated. I tried Resizing the bitmap of the picture but it did not help.
Here is the bitmap initialization
PackageManager m = getActivity().getPackageManager();
String s = getActivity().getPackageName();
PackageInfo p = null;
try {
p = m.getPackageInfo(s, 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
s = p.applicationInfo.dataDir;
//String root = Environment.getExternalStorageDirectory().toString();
s += "/player_photos/" + player.getPlayerId() + ".png";
Bitmap bMap = BitmapFactory.decodeFile(s);
Resources res = getResources();
BitmapDrawable icon = new BitmapDrawable(res, bMap);
playerDP.setImageDrawable(icon);
}