Perfect circle around TextViews - android

I'm looking for a layout like the L Clock:
More specifically, the 7 letters with circles around it.
I really want to make a layout with 7 circles with the same size (in any device) one next to the other (horizontally).
What I tried to do was:
To make a LinearLayout with orientation=horizontal.
To make a "oval shape" to apply on 7 TextViews inside this LinearLayout.
Then I put on each TextView a weight=1.
That didn't work (and I was not sure if it was a good idea since I heard we must avoid using "weight") and, I tried to creat a custom textview and override the onMeasure method.
Class
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(height, height);
}
Layout
<br.com.sibela.testtextviewsamesize.component.RoundTextView
android:layout_margin="10dp"
android:textAlignment="center"
android:layout_weight="1"
android:background="#drawable/circular_textview"
android:text="T"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Shape:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#4488FF" />
</shape>
Now I need to know two things:
1) How do I make the 7 rounded circles with the same size ocupping the whole width of the screen?
2) Should I really avoid using weight?
UPDATE:
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:context=".MainActivity">
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circular_textview"
android:minHeight="1dp"
android:minWidth="1dp"
android:text="S" />
<Button
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circular_textview"
android:minHeight="1dp"
android:minWidth="1dp"
android:text="M" />
<Button
android:id="#+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circular_textview"
android:minHeight="1dp"
android:minWidth="1dp"
android:text="T" />
<Button
android:id="#+id/btn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circular_textview"
android:minHeight="1dp"
android:minWidth="1dp"
android:text="W" />
<Button
android:id="#+id/btn5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circular_textview"
android:minHeight="1dp"
android:minWidth="1dp"
android:text="T" />
<Button
android:id="#+id/btn6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circular_textview"
android:minHeight="1dp"
android:minWidth="1dp"
android:text="F" />
<Button
android:id="#+id/btn7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circular_textview"
android:minHeight="1dp"
android:minWidth="1dp"
android:text="S" />
</LinearLayout>
Class:
package br.com.sibela.testtextviewsamesize;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button btn1;
Button btn2;
Button btn3;
Button btn4;
Button btn5;
Button btn6;
Button btn7;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
btn3 = (Button) findViewById(R.id.btn3);
btn4 = (Button) findViewById(R.id.btn4);
btn5 = (Button) findViewById(R.id.btn5);
btn6 = (Button) findViewById(R.id.btn6);
btn7 = (Button) findViewById(R.id.btn7);
DisplayMetrics display = this.getResources().getDisplayMetrics();
int width = (display.widthPixels)/7;
btn1.setWidth(width);
btn2.setWidth(width);
btn3.setWidth(width);
btn4.setWidth(width);
btn5.setWidth(width);
btn6.setWidth(width);
btn7.setWidth(width);
btn1.setHeight(width);
btn2.setHeight(width);
btn3.setHeight(width);
btn4.setHeight(width);
btn5.setHeight(width);
btn6.setHeight(width);
btn7.setHeight(width);
}
}
Shape:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#4488FF" />
</shape>

You're in for a lot of trouble if you choose to subclass TextView. TextView does a lot of things, but you don't need it here.
Instead, make a custom view, use it once for each letter, and in the onDraw for the view, simply draw the circle and letter into the Canvas as you want them to appear (using drawText and drawCircle). You can still arrange your custom views any way you like, but you won't have to guess what TextView is going to do with your text because YOU control its rendering instead.
It will appear to be extra work up front to make a custom view, but you will save yourself a lot of trouble in the long run.

One option is, get 7 images, and you can use this CircleImageView class to make it as circular.
public class CircleImageView extends ImageView {
private static final ImageView.ScaleType SCALE_TYPE = ImageView.ScaleType.CENTER_CROP;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 2;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
private static final boolean DEFAULT_BORDER_OVERLAY = false;
private final RectF mDrawableRect = new RectF();
private final RectF mBorderRect = new RectF();
private final Matrix mShaderMatrix = new Matrix();
private final Paint mBitmapPaint = new Paint();
private final Paint mBorderPaint = new Paint();
private final Paint mFillPaint = new Paint();
private int mBorderColor = DEFAULT_BORDER_COLOR;
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
private int mFillColor = DEFAULT_FILL_COLOR;
private Bitmap mBitmap;
private BitmapShader mBitmapShader;
private int mBitmapWidth;
private int mBitmapHeight;
private float mDrawableRadius;
private float mBorderRadius;
private ColorFilter mColorFilter;
private boolean mReady;
private boolean mSetupPending;
private boolean mBorderOverlay;
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
a.recycle();
init();
}
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
#Override
public ScaleType getScaleType() {
return SCALE_TYPE;
}
#Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
}
}
#Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (adjustViewBounds) {
throw new IllegalArgumentException("adjustViewBounds not supported.");
}
}
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
if (mFillColor != Color.TRANSPARENT) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
}
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
if (mBorderWidth != 0) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(#ColorInt int borderColor) {
if (borderColor == mBorderColor) {
return;
}
mBorderColor = borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
public void setBorderColorResource(#ColorRes int borderColorRes) {
setBorderColor(getContext().getResources().getColor(borderColorRes));
}
public int getFillColor() {
return mFillColor;
}
public void setFillColor(#ColorInt int fillColor) {
if (fillColor == mFillColor) {
return;
}
mFillColor = fillColor;
mFillPaint.setColor(fillColor);
invalidate();
}
public void setFillColorResource(#ColorRes int fillColorRes) {
setFillColor(getContext().getResources().getColor(fillColorRes));
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth == mBorderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
public boolean isBorderOverlay() {
return mBorderOverlay;
}
public void setBorderOverlay(boolean borderOverlay) {
if (borderOverlay == mBorderOverlay) {
return;
}
mBorderOverlay = borderOverlay;
setup();
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mBitmap = bm;
setup();
}
#Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
mBitmap = getBitmapFromDrawable(drawable);
setup();
}
#Override
public void setImageResource(#DrawableRes int resId) {
super.setImageResource(resId);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
#Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
setup();
}
#Override
public void setColorFilter(ColorFilter cf) {
if (cf == mColorFilter) {
return;
}
mColorFilter = cf;
mBitmapPaint.setColorFilter(mColorFilter);
invalidate();
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void setup() {
if (!mReady) {
mSetupPending = true;
return;
}
if (getWidth() == 0 && getHeight() == 0) {
return;
}
if (mBitmap == null) {
invalidate();
return;
}
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setAntiAlias(true);
mFillPaint.setColor(mFillColor);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(0, 0, getWidth(), getHeight());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay) {
mDrawableRect.inset(mBorderWidth, mBorderWidth);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
updateShaderMatrix();
invalidate();
}
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
}
Instead of ImageView use CircleImageView in both java and XML.
Hope it helps! :)

Related

Android - MaterialCardView corner radius not showing up in fragments

I created a cornerRadius card view and my codes work well in activity but the problem now is that the cardview does not show the rounded edges and elevation in fragment but it shows in the design codes and in activity. my codes are shown blow:
raounded_corners.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:focusable="true"
android:clickable="true"
android:background="#color/white"
android:layout_height="match_parent">
<com.google.android.material.card.MaterialCardView
android:id="#+id/text_bg"
android:layout_width="110dp"
android:layout_height="110dp"
app:cardBackgroundColor="#color/green_500"
app:cardCornerRadius="50dp"
app:cardElevation="5dp"
android:layout_gravity="center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/image_session"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:src="#drawable/photo_male_7" />
</com.google.android.material.card.MaterialCardView>
</RelativeLayout>
In Fragment
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.raounded_corners,container,false);
return v;
}
raounded_corners.xml layout cornerRadius showing in activity but not showing in fragment
How to fix this.
In Activity
in fragment
If you are trying to make the imageview circular, I propose this approach.Create the custom view and set it in your xml. It works perfectly. If this helps you, an upvote will be appreciated.
Create a custom Circular view like shown below. CircleImageView.java
package com.fishpott.fishpott5.Views;
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.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.fishpott.fishpott5.R;
public class CircleImageView extends AppCompatImageView {
private static final ImageView.ScaleType SCALE_TYPE = ImageView.ScaleType.CENTER_CROP;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 2;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
private static final boolean DEFAULT_BORDER_OVERLAY = false;
private final RectF mDrawableRect = new RectF();
private final RectF mBorderRect = new RectF();
private final Matrix mShaderMatrix = new Matrix();
private final Paint mBitmapPaint = new Paint();
private final Paint mBorderPaint = new Paint();
private final Paint mFillPaint = new Paint();
private int mBorderColor = DEFAULT_BORDER_COLOR;
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
private int mFillColor = DEFAULT_FILL_COLOR;
private Bitmap mBitmap;
private BitmapShader mBitmapShader;
private int mBitmapWidth;
private int mBitmapHeight;
private float mDrawableRadius;
private float mBorderRadius;
private ColorFilter mColorFilter;
private boolean mReady;
private boolean mSetupPending;
private boolean mBorderOverlay;
private boolean mDisableCircularTransformation;
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
a.recycle();
init();
}
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
#Override
public ImageView.ScaleType getScaleType() {
return SCALE_TYPE;
}
#Override
public void setScaleType(ImageView.ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
}
}
#Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (adjustViewBounds) {
throw new IllegalArgumentException("adjustViewBounds not supported.");
}
}
#Override
protected void onDraw(Canvas canvas) {
if (mDisableCircularTransformation) {
super.onDraw(canvas);
return;
}
if (mBitmap == null) {
return;
}
if (mFillColor != Color.TRANSPARENT) {
canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint);
}
canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint);
if (mBorderWidth > 0) {
canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
#Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
setup();
}
#Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
super.setPaddingRelative(start, top, end, bottom);
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(#ColorInt int borderColor) {
if (borderColor == mBorderColor) {
return;
}
mBorderColor = borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
/**
* #deprecated Use {#link #setBorderColor(int)} instead
*/
#Deprecated
public void setBorderColorResource(#ColorRes int borderColorRes) {
setBorderColor(getContext().getResources().getColor(borderColorRes));
}
/**
* Return the color drawn behind the circle-shaped drawable.
*
* #return The color drawn behind the drawable
*
* #deprecated Fill color support is going to be removed in the future
*/
#Deprecated
public int getFillColor() {
return mFillColor;
}
/**
* Set a color to be drawn behind the circle-shaped drawable. Note that
* this has no effect if the drawable is opaque or no drawable is set.
*
* #param fillColor The color to be drawn behind the drawable
*
* #deprecated Fill color support is going to be removed in the future
*/
#Deprecated
public void setFillColor(#ColorInt int fillColor) {
if (fillColor == mFillColor) {
return;
}
mFillColor = fillColor;
mFillPaint.setColor(fillColor);
invalidate();
}
/**
* Set a color to be drawn behind the circle-shaped drawable. Note that
* this has no effect if the drawable is opaque or no drawable is set.
*
* #param fillColorRes The color resource to be resolved to a color and
* drawn behind the drawable
*
* #deprecated Fill color support is going to be removed in the future
*/
#Deprecated
public void setFillColorResource(#ColorRes int fillColorRes) {
setFillColor(getContext().getResources().getColor(fillColorRes));
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth == mBorderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
public boolean isBorderOverlay() {
return mBorderOverlay;
}
public void setBorderOverlay(boolean borderOverlay) {
if (borderOverlay == mBorderOverlay) {
return;
}
mBorderOverlay = borderOverlay;
setup();
}
public boolean isDisableCircularTransformation() {
return mDisableCircularTransformation;
}
public void setDisableCircularTransformation(boolean disableCircularTransformation) {
if (mDisableCircularTransformation == disableCircularTransformation) {
return;
}
mDisableCircularTransformation = disableCircularTransformation;
initializeBitmap();
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
initializeBitmap();
}
#Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
initializeBitmap();
}
#Override
public void setImageResource(#DrawableRes int resId) {
super.setImageResource(resId);
initializeBitmap();
}
#Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
initializeBitmap();
}
#Override
public void setColorFilter(ColorFilter cf) {
if (cf == mColorFilter) {
return;
}
mColorFilter = cf;
applyColorFilter();
invalidate();
}
#Override
public ColorFilter getColorFilter() {
return mColorFilter;
}
private void applyColorFilter() {
if (mBitmapPaint != null) {
mBitmapPaint.setColorFilter(mColorFilter);
}
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void initializeBitmap() {
if (mDisableCircularTransformation) {
mBitmap = null;
} else {
mBitmap = getBitmapFromDrawable(getDrawable());
}
setup();
}
private void setup() {
if (!mReady) {
mSetupPending = true;
return;
}
if (getWidth() == 0 && getHeight() == 0) {
return;
}
if (mBitmap == null) {
invalidate();
return;
}
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setAntiAlias(true);
mFillPaint.setColor(mFillColor);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(calculateBounds());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay && mBorderWidth > 0) {
mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
applyColorFilter();
updateShaderMatrix();
invalidate();
}
private RectF calculateBounds() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableWidth, availableHeight);
float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
float top = getPaddingTop() + (availableHeight - sideLength) / 2f;
return new RectF(left, top, left + sideLength, top + sideLength);
}
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
}
Set the view in your xml
<com.fishpott.fishpott5.Views.CircleImageView
android:id="#+id/activity_setprofilepicture_profilepicture_imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/none"
android:src="#drawable/setprofilepicture_activity_imageholder_default_image"
app:civ_border_color="#android:color/transparent"
app:civ_border_width="0dp" />
The reason you see "Views" in my xml call of the CircleImageView is because my CircleImageView.java is in "Views" folder/package.

ImageView with only one rounded corner

I'm trying to make one rounded corner of ImageView like in the picture below but with bottom right corner. Tried using background shape but it's not working at all. All images loaded by Glide. Should i use something like ViewOutlineProvider? Is there are an efficient way to do this? Thanks!
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<corners
android:radius="2dp"
android:bottomRightRadius="20dp"
android:bottomLeftRadius="0dp"
android:topLeftRadius="0dp"
android:topRightRadius="0dp"/>
</shape>
With jetpack compose you can apply the clip Modifier using a RoundedCornerShape:
Image(painterResource(id = R.drawable.xxx),
contentDescription = "xxxx",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(xx.dp,xx.dp)
.clip(RoundedCornerShape(topStart = 12.dp)),
)
With The Material Components library you can use the ShapeableImageView (introduced with the version 1.2.0-alpha03).
Just use something like:
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/image_view"
android:scaleType="centerInside"
android:adjustViewBounds="true"
../>
then in your code you can apply the ShapeAppearanceModel with:
ShapeableImageView imageView = findViewById(R.id.image_view);
float radius = getResources().getDimension(R.dimen.default_corner_radius);
imageView.setShapeAppearanceModel(imageView.getShapeAppearanceModel()
.toBuilder()
.setTopRightCorner(CornerFamily.ROUNDED,radius)
.build());
You can also apply in the xml the shapeAppearanceOverlay parameter:
<com.google.android.material.imageview.ShapeableImageView
app:shapeAppearanceOverlay="#style/customRroundedImageView"
app:srcCompat="#drawable/ic_image" />
with:
<style name="customRoundedImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">0dp</item>
<item name="cornerSizeTopRight">8dp</item>
</style>
Also if you want to get rid of writing code in ".java" file. Then you can define style like below and just add it to your ShapeableImageView:
<com.google.android.material.imageview.ShapeableImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ex_image"
app:shapeAppearanceOverlay="#style/roundedImageView"
/>
then:
<style name="roundedImageView" parent="">
<item name="cornerFamilyTopRight">rounded</item>
<item name="cornerSizeTopRight">30dp</item>
</style>
this is your main layout file which uses a custom drawable "round_one.xml"file. just copy and paste this code.
it will hopefully meet your requirements.
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:elevation="#dimen/_10sdp"
android:background="#color/white"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/round_one"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="#dimen/_80sdp"
android:layout_gravity="center"
android:scaleType="fitXY"
android:src="#android:drawable/ic_menu_day" />
<TextView
android:id="#+id/textView22"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="title goes here" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="Secondary text"
/>
</LinearLayout>
</androidx.cardview.widget.CardView>
round_one.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#color/gray" />
<corners android:topRightRadius="50dp" />
</shape>
To round only one corner of imageview follow below steps and code:
Add below file to your project RoundCornerImageView.java
package com.skd.stackdemo;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
public class RoundCornerImageView extends ImageView {
public static final String TAG = "RoundCornerImageView";
private int mResource = 0;
private static final ScaleType[] sScaleTypeArray = {
ScaleType.MATRIX,
ScaleType.FIT_XY,
ScaleType.FIT_START,
ScaleType.FIT_CENTER,
ScaleType.FIT_END,
ScaleType.CENTER,
ScaleType.CENTER_CROP,
ScaleType.CENTER_INSIDE
};
// Set default scale type to FIT_CENTER, which is default scale type of
// original ImageView.
private ScaleType mScaleType = ScaleType.FIT_CENTER;
private float mLeftTopCornerRadius = 0.0f;
private float mRightTopCornerRadius = 0.0f;
private float mLeftBottomCornerRadius = 0.0f;
private float mRightBottomCornerRadius = 0.0f;
private float mBorderWidth = 0.0f;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
private boolean isOval = false;
private Drawable mDrawable;
private float[] mRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 };
public RoundCornerImageView(Context context) {
super(context);
}
public RoundCornerImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundCornerImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SelectableRoundedImageView, defStyle, 0);
final int index = a.getInt(R.styleable.SelectableRoundedImageView_android_scaleType, -1);
if (index >= 0) {
setScaleType(sScaleTypeArray[index]);
}
mLeftTopCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_left_top_corner_radius, 0);
mRightTopCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_right_top_corner_radius, 0);
mLeftBottomCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_left_bottom_corner_radius, 0);
mRightBottomCornerRadius = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_right_bottom_corner_radius, 0);
if (mLeftTopCornerRadius < 0.0f || mRightTopCornerRadius < 0.0f
|| mLeftBottomCornerRadius < 0.0f || mRightBottomCornerRadius < 0.0f) {
throw new IllegalArgumentException("radius values cannot be negative.");
}
mRadii = new float[] {
mLeftTopCornerRadius, mLeftTopCornerRadius,
mRightTopCornerRadius, mRightTopCornerRadius,
mRightBottomCornerRadius, mRightBottomCornerRadius,
mLeftBottomCornerRadius, mLeftBottomCornerRadius };
mBorderWidth = a.getDimensionPixelSize(
R.styleable.SelectableRoundedImageView_sriv_border_width, 0);
if (mBorderWidth < 0) {
throw new IllegalArgumentException("border width cannot be negative.");
}
mBorderColor = a
.getColorStateList(R.styleable.SelectableRoundedImageView_sriv_border_color);
if (mBorderColor == null) {
mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
}
isOval = a.getBoolean(R.styleable.SelectableRoundedImageView_sriv_oval, false);
a.recycle();
updateDrawable();
}
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
invalidate();
}
#Override
public ScaleType getScaleType() {
return mScaleType;
}
#Override
public void setScaleType(ScaleType scaleType) {
super.setScaleType(scaleType);
mScaleType = scaleType;
updateDrawable();
}
#Override
public void setImageDrawable(Drawable drawable) {
mResource = 0;
mDrawable = RoundCornerDrawable.fromDrawable(drawable, getResources());
super.setImageDrawable(mDrawable);
updateDrawable();
}
#Override
public void setImageBitmap(Bitmap bm) {
mResource = 0;
mDrawable = RoundCornerDrawable.fromBitmap(bm, getResources());
super.setImageDrawable(mDrawable);
updateDrawable();
}
#Override
public void setImageResource(int resId) {
if (mResource != resId) {
mResource = resId;
mDrawable = resolveResource();
super.setImageDrawable(mDrawable);
updateDrawable();
}
}
#Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
setImageDrawable(getDrawable());
}
private Drawable resolveResource() {
Resources rsrc = getResources();
if (rsrc == null) {
return null;
}
Drawable d = null;
if (mResource != 0) {
try {
d = rsrc.getDrawable(mResource);
} catch (Resources.NotFoundException e) {
Log.w(TAG, "Unable to find resource: " + mResource, e);
// Don't try again.
mResource = 0;
}
}
return RoundCornerDrawable.fromDrawable(d, getResources());
}
private void updateDrawable() {
if (mDrawable == null) {
return;
}
((RoundCornerDrawable) mDrawable).setScaleType(mScaleType);
((RoundCornerDrawable) mDrawable).setCornerRadii(mRadii);
((RoundCornerDrawable) mDrawable).setBorderWidth(mBorderWidth);
((RoundCornerDrawable) mDrawable).setBorderColor(mBorderColor);
((RoundCornerDrawable) mDrawable).setOval(isOval);
}
public float getCornerRadius() {
return mLeftTopCornerRadius;
}
/**
* Set radii for each corner.
*
* #param leftTop The desired radius for left-top corner in dip.
* #param rightTop The desired desired radius for right-top corner in dip.
* #param leftBottom The desired radius for left-bottom corner in dip.
* #param rightBottom The desired radius for right-bottom corner in dip.
*
*/
public void setCornerRadiiDP(float leftTop, float rightTop, float leftBottom, float rightBottom) {
final float density = getResources().getDisplayMetrics().density;
final float lt = leftTop * density;
final float rt = rightTop * density;
final float lb = leftBottom * density;
final float rb = rightBottom * density;
mRadii = new float[] { lt, lt, rt, rt, rb, rb, lb, lb };
updateDrawable();
}
public float getBorderWidth() {
return mBorderWidth;
}
/**
* Set border width.
*
* #param width
* The desired width in dip.
*/
public void setBorderWidthDP(float width) {
float scaledWidth = getResources().getDisplayMetrics().density * width;
if (mBorderWidth == scaledWidth) {
return;
}
mBorderWidth = scaledWidth;
updateDrawable();
invalidate();
}
public int getBorderColor() {
return mBorderColor.getDefaultColor();
}
public void setBorderColor(int color) {
setBorderColor(ColorStateList.valueOf(color));
}
public ColorStateList getBorderColors() {
return mBorderColor;
}
public void setBorderColor(ColorStateList colors) {
if (mBorderColor.equals(colors)) {
return;
}
mBorderColor = (colors != null) ? colors : ColorStateList
.valueOf(DEFAULT_BORDER_COLOR);
updateDrawable();
if (mBorderWidth > 0) {
invalidate();
}
}
public boolean isOval() {
return isOval;
}
public void setOval(boolean oval) {
isOval = oval;
updateDrawable();
invalidate();
}
static class RoundCornerDrawable extends Drawable {
private static final String TAG = "RoundCornerDrawable";
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private RectF mBounds = new RectF();
private RectF mBorderBounds = new RectF();
private final RectF mBitmapRect = new RectF();
private final int mBitmapWidth;
private final int mBitmapHeight;
private final Paint mBitmapPaint;
private final Paint mBorderPaint;
private BitmapShader mBitmapShader;
private float[] mRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 };
private float[] mBorderRadii = new float[] { 0, 0, 0, 0, 0, 0, 0, 0 };
private boolean mOval = false;
private float mBorderWidth = 0;
private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
// Set default scale type to FIT_CENTER, which is default scale type of
// original ImageView.
private ScaleType mScaleType = ScaleType.FIT_CENTER;
private Path mPath = new Path();
private Bitmap mBitmap;
private boolean mBoundsConfigured = false;
public RoundCornerDrawable(Bitmap bitmap, Resources r) {
mBitmap = bitmap;
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
if (bitmap != null) {
mBitmapWidth = bitmap.getScaledWidth(r.getDisplayMetrics());
mBitmapHeight = bitmap.getScaledHeight(r.getDisplayMetrics());
} else {
mBitmapWidth = mBitmapHeight = -1;
}
mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight);
mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBitmapPaint.setStyle(Paint.Style.FILL);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
mBorderPaint.setStrokeWidth(mBorderWidth);
}
public static RoundCornerDrawable fromBitmap(Bitmap bitmap, Resources r) {
if (bitmap != null) {
return new RoundCornerDrawable(bitmap, r);
} else {
return null;
}
}
#SuppressLint("LongLogTag")
public static Drawable fromDrawable(Drawable drawable, Resources r) {
if (drawable != null) {
if (drawable instanceof RoundCornerDrawable) {
return drawable;
} else if (drawable instanceof LayerDrawable) {
LayerDrawable ld = (LayerDrawable) drawable;
final int num = ld.getNumberOfLayers();
for (int i = 0; i < num; i++) {
Drawable d = ld.getDrawable(i);
ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d, r));
}
return ld;
}
Bitmap bm = drawableToBitmap(drawable);
if (bm != null) {
return new RoundCornerDrawable(bm, r);
} else {
Log.w(TAG, "Failed to create bitmap from drawable!");
}
}
return drawable;
}
public static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap bitmap;
int width = Math.max(drawable.getIntrinsicWidth(), 2);
int height = Math.max(drawable.getIntrinsicHeight(), 2);
try {
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
} catch (IllegalArgumentException e) {
e.printStackTrace();
bitmap = null;
}
return bitmap;
}
#Override
public boolean isStateful() {
return mBorderColor.isStateful();
}
#Override
protected boolean onStateChange(int[] state) {
int newColor = mBorderColor.getColorForState(state, 0);
if (mBorderPaint.getColor() != newColor) {
mBorderPaint.setColor(newColor);
return true;
} else {
return super.onStateChange(state);
}
}
private void configureBounds(Canvas canvas) {
// I have discovered a truly marvelous explanation of this,
// which this comment space is too narrow to contain. :)
// If you want to understand what's going on here,
// See http://www.joooooooooonhokim.com/?p=289
Rect clipBounds = canvas.getClipBounds();
Matrix canvasMatrix = canvas.getMatrix();
if (ScaleType.CENTER == mScaleType) {
mBounds.set(clipBounds);
} else if (ScaleType.CENTER_CROP == mScaleType) {
applyScaleToRadii(canvasMatrix);
mBounds.set(clipBounds);
} else if (ScaleType.FIT_XY == mScaleType) {
Matrix m = new Matrix();
m.setRectToRect(mBitmapRect, new RectF(clipBounds), Matrix.ScaleToFit.FILL);
mBitmapShader.setLocalMatrix(m);
mBounds.set(clipBounds);
} else if (ScaleType.FIT_START == mScaleType || ScaleType.FIT_END == mScaleType
|| ScaleType.FIT_CENTER == mScaleType || ScaleType.CENTER_INSIDE == mScaleType) {
applyScaleToRadii(canvasMatrix);
mBounds.set(mBitmapRect);
} else if (ScaleType.MATRIX == mScaleType) {
applyScaleToRadii(canvasMatrix);
mBounds.set(mBitmapRect);
}
}
private void applyScaleToRadii(Matrix m) {
float[] values = new float[9];
m.getValues(values);
for (int i = 0; i < mRadii.length; i++) {
mRadii[i] = mRadii[i] / values[0];
}
}
private void adjustCanvasForBorder(Canvas canvas) {
Matrix canvasMatrix = canvas.getMatrix();
final float[] values = new float[9];
canvasMatrix.getValues(values);
final float scaleFactorX = values[0];
final float scaleFactorY = values[4];
final float translateX = values[2];
final float translateY = values[5];
final float newScaleX = mBounds.width()
/ (mBounds.width() + mBorderWidth + mBorderWidth);
final float newScaleY = mBounds.height()
/ (mBounds.height() + mBorderWidth + mBorderWidth);
canvas.scale(newScaleX, newScaleY);
if (ScaleType.FIT_START == mScaleType || ScaleType.FIT_END == mScaleType
|| ScaleType.FIT_XY == mScaleType || ScaleType.FIT_CENTER == mScaleType
|| ScaleType.CENTER_INSIDE == mScaleType || ScaleType.MATRIX == mScaleType) {
canvas.translate(mBorderWidth, mBorderWidth);
} else if (ScaleType.CENTER == mScaleType || ScaleType.CENTER_CROP == mScaleType) {
// First, make translate values to 0
canvas.translate(
-translateX / (newScaleX * scaleFactorX),
-translateY / (newScaleY * scaleFactorY));
// Then, set the final translate values.
canvas.translate(-(mBounds.left - mBorderWidth), -(mBounds.top - mBorderWidth));
}
}
private void adjustBorderWidthAndBorderBounds(Canvas canvas) {
Matrix canvasMatrix = canvas.getMatrix();
final float[] values = new float[9];
canvasMatrix.getValues(values);
final float scaleFactor = values[0];
float viewWidth = mBounds.width() * scaleFactor;
mBorderWidth = (mBorderWidth * mBounds.width()) / (viewWidth - (2 * mBorderWidth));
mBorderPaint.setStrokeWidth(mBorderWidth);
mBorderBounds.set(mBounds);
mBorderBounds.inset(- mBorderWidth / 2, - mBorderWidth / 2);
}
private void setBorderRadii() {
for (int i = 0; i < mRadii.length; i++) {
if (mRadii[i] > 0) {
mBorderRadii[i] = mRadii[i];
mRadii[i] = mRadii[i] - mBorderWidth;
}
}
}
#Override
public void draw(Canvas canvas) {
canvas.save();
if (!mBoundsConfigured) {
configureBounds(canvas);
if (mBorderWidth > 0) {
adjustBorderWidthAndBorderBounds(canvas);
setBorderRadii();
}
mBoundsConfigured = true;
}
if (mOval) {
if (mBorderWidth > 0) {
adjustCanvasForBorder(canvas);
mPath.addOval(mBounds, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
mPath.reset();
mPath.addOval(mBorderBounds, Path.Direction.CW);
canvas.drawPath(mPath, mBorderPaint);
} else {
mPath.addOval(mBounds, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
}
} else {
if (mBorderWidth > 0) {
adjustCanvasForBorder(canvas);
mPath.addRoundRect(mBounds, mRadii, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
mPath.reset();
mPath.addRoundRect(mBorderBounds, mBorderRadii, Path.Direction.CW);
canvas.drawPath(mPath, mBorderPaint);
} else {
mPath.addRoundRect(mBounds, mRadii, Path.Direction.CW);
canvas.drawPath(mPath, mBitmapPaint);
}
}
canvas.restore();
}
public void setCornerRadii(float[] radii) {
if (radii == null)
return;
if (radii.length != 8) {
throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
}
for (int i = 0; i < radii.length; i++) {
mRadii[i] = radii[i];
}
}
#Override
public int getOpacity() {
return (mBitmap == null || mBitmap.hasAlpha() || mBitmapPaint.getAlpha() < 255) ? PixelFormat.TRANSLUCENT
: PixelFormat.OPAQUE;
}
#Override
public void setAlpha(int alpha) {
mBitmapPaint.setAlpha(alpha);
invalidateSelf();
}
#Override
public void setColorFilter(ColorFilter cf) {
mBitmapPaint.setColorFilter(cf);
invalidateSelf();
}
#Override
public void setDither(boolean dither) {
mBitmapPaint.setDither(dither);
invalidateSelf();
}
#Override
public void setFilterBitmap(boolean filter) {
mBitmapPaint.setFilterBitmap(filter);
invalidateSelf();
}
#Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
#Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
public float getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(float width) {
mBorderWidth = width;
mBorderPaint.setStrokeWidth(width);
}
public int getBorderColor() {
return mBorderColor.getDefaultColor();
}
public void setBorderColor(int color) {
setBorderColor(ColorStateList.valueOf(color));
}
public ColorStateList getBorderColors() {
return mBorderColor;
}
/**
* Controls border color of this ImageView.
*
* #param colors
* The desired border color. If it's null, no border will be
* drawn.
*
*/
public void setBorderColor(ColorStateList colors) {
if (colors == null) {
mBorderWidth = 0;
mBorderColor = ColorStateList.valueOf(Color.TRANSPARENT);
mBorderPaint.setColor(Color.TRANSPARENT);
} else {
mBorderColor = colors;
mBorderPaint.setColor(mBorderColor.getColorForState(getState(),
DEFAULT_BORDER_COLOR));
}
}
public boolean isOval() {
return mOval;
}
public void setOval(boolean oval) {
mOval = oval;
}
public ScaleType getScaleType() {
return mScaleType;
}
public void setScaleType(ScaleType scaleType) {
if (scaleType == null) {
return;
}
mScaleType = scaleType;
}
}
}
Add styleable to attr file under res folder
<declare-styleable name="RoundCornerImageView">
<attr name="sriv_left_top_corner_radius" format="dimension" />
<attr name="sriv_right_top_corner_radius" format="dimension" />
<attr name="sriv_left_bottom_corner_radius" format="dimension" />
<attr name="sriv_right_bottom_corner_radius" format="dimension" />
<attr name="sriv_border_width" format="dimension" />
<attr name="sriv_border_color" format="color" />
<attr name="sriv_oval" format="boolean" />
<attr name="android:scaleType" />
</declare-styleable>
Used in XML file:
<com.skd.stackdemo.RoundCornerImageView
android:layout_width="300dp"
android:layout_height="300dp"
android:src="#drawable/android"
android:scaleType="centerCrop"
app:sriv_left_top_corner_radius="0dp"
app:sriv_right_top_corner_radius="20dp"
app:sriv_left_bottom_corner_radius="0dp"
app:sriv_right_bottom_corner_radius="0dp"
app:sriv_oval="false" />
Output for above code is:
For more information please check this github project:SelectableRoundedImageView
I hope it works for you

Setting border to circular imageview is not working when paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

I want to set border to circular Image view and also want the image view to be inside the circle, so below is my code-
public static Bitmap getRoundedRectBitmap(Bitmap bitmap, int pixels) {
Bitmap result = null;
try {
result = Bitmap.createBitmap(pixels, pixels, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
Rect rect = new Rect(0, 0, pixels*2, pixels*2);
// paint.setAntiAlias(true);
//; canvas.drawARGB(0, 0, 0, 0);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
canvas.drawCircle(pixels/2, pixels/2, pixels/2, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(15);
paint.setColor(Color.parseColor("#17B3F0"));
canvas.drawCircle(pixels/2+0.7f, pixels/2+0.7f, pixels/2+0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
} catch (NullPointerException e) {
} catch (OutOfMemoryError o) {
}
return result;
}
So the problem is with the line
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
If I am commenting this line, it's making all the properties added to paint object visible but making image comes out of the circle.
But I want the Image to be inside the circle as well as a border to be set.
Any help is appreciated.Thanks.
Updated from Here -
I have created a custom class which MyCustomAdapter and Inside getView I am setting the imageView onStateChangeListener as below -
#Override
public View getView(int position, View convertView, ViewGroup parent) {
int type = getItemViewType(position);
View view = inflater.inflate(type == List_Section ? R.layout.section : R.layout.listitem, parent, false);
if (type == List_Section) {
departments = ((TextView) view.findViewById(R.id.tv_li_section));
departments.setText(list_complete_data.get(position).toString());
} else {
//StateListDrawable stateListDrawable = (StateListDrawable) view.getBackground();
Emp_name = (TextView) view.findViewById(R.id.emp_name);
Emp_number = (TextView) view.findViewById(R.id.emp_no);
small_profile =(CircleImageView)view.findViewById(R.id.small_profile);
Log.e(TAG,"small_profile====="+small_profile);
Log.e(TAG,"inside getView=====");
small_profile.setOnStateChangedListener(new OnStateChangeListener() {
#Override
public void onStateChanged(int state) {
Log.e(TAG,"onStateistener and state=="+state+".,,,R.attr.state_on==="+R.attr.state_on+",,,R.attr.state_off=="+R.attr.state_off);
switch (state){
case R.attr.state_on :
small_profile.setBorderColor(Color.parseColor("#ffffff"));
break;
case R.attr.state_off:
small_profile.setBorderColor(Color.parseColor("#000000"));
break;
}
}
});
EDIT : I have made some changes to the code according to your requirements:
add the following interface to your project:
public interface OnStateChangeListener {
void onStateChanged(int state);
}
and then make then I made some changes in the CircleImageView
public class CircleImageView extends ImageView implements View.OnTouchListener {
private static final int[] mStates = { R.attr.state_notset, R.attr.state_on, R.attr.state_off };
private int mStateIndex = 0; // first state is "notset"
private OnStateChangeListener mListener;
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 2;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
private static final boolean DEFAULT_BORDER_OVERLAY = false;
private final RectF mDrawableRect = new RectF();
private final RectF mBorderRect = new RectF();
private final Matrix mShaderMatrix = new Matrix();
private final Paint mBitmapPaint = new Paint();
private final Paint mBorderPaint = new Paint();
private final Paint mFillPaint = new Paint();
private int mBorderColor = DEFAULT_BORDER_COLOR;
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
private int mFillColor = DEFAULT_FILL_COLOR;
private Bitmap mBitmap;
private BitmapShader mBitmapShader;
private int mBitmapWidth;
private int mBitmapHeight;
private float mDrawableRadius;
private float mBorderRadius;
private ColorFilter mColorFilter;
private boolean mReady;
private boolean mSetupPending;
private boolean mBorderOverlay;
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
a.recycle();
init();
}
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
#Override
public ScaleType getScaleType() {
return SCALE_TYPE;
}
#Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
}
}
#Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (adjustViewBounds) {
throw new IllegalArgumentException("adjustViewBounds not supported.");
}
}
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
if (mFillColor != Color.TRANSPARENT) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
}
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
if (mBorderWidth != 0) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(#ColorInt int borderColor) {
if (borderColor == mBorderColor) {
return;
}
mBorderColor = borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
public void setBorderColorResource(#ColorRes int borderColorRes) {
setBorderColor(getContext().getResources().getColor(borderColorRes));
}
public int getFillColor() {
return mFillColor;
}
public void setFillColor(#ColorInt int fillColor) {
if (fillColor == mFillColor) {
return;
}
mFillColor = fillColor;
mFillPaint.setColor(fillColor);
invalidate();
}
public void setFillColorResource(#ColorRes int fillColorRes) {
setFillColor(getContext().getResources().getColor(fillColorRes));
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth == mBorderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
public boolean isBorderOverlay() {
return mBorderOverlay;
}
public void setBorderOverlay(boolean borderOverlay) {
if (borderOverlay == mBorderOverlay) {
return;
}
mBorderOverlay = borderOverlay;
setup();
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mBitmap = bm;
setup();
}
#Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
mBitmap = getBitmapFromDrawable(drawable);
setup();
}
#Override
public void setImageResource(#DrawableRes int resId) {
super.setImageResource(resId);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
#Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
setup();
}
#Override
public void setColorFilter(ColorFilter cf) {
if (cf == mColorFilter) {
return;
}
mColorFilter = cf;
applyColorFilter();
invalidate();
}
#Override
public ColorFilter getColorFilter() {
return mColorFilter;
}
private void applyColorFilter() {
if (mBitmapPaint != null) {
mBitmapPaint.setColorFilter(mColorFilter);
}
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void setup() {
if (!mReady) {
mSetupPending = true;
return;
}
if (getWidth() == 0 && getHeight() == 0) {
return;
}
if (mBitmap == null) {
invalidate();
return;
}
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setAntiAlias(true);
mFillPaint.setColor(mFillColor);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(0, 0, getWidth(), getHeight());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay) {
mDrawableRect.inset(mBorderWidth, mBorderWidth);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
applyColorFilter();
updateShaderMatrix();
invalidate();
}
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
#Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace+1);
int [] state = { mStates[mStateIndex] };
mergeDrawableStates(drawableState, state);
return drawableState;
}
public void setOnStateChangedListener(OnStateChangeListener l) {
this.mListener = l;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("STATETOUCH", "onTouch: down");
mStateIndex = 1;
if(mListener != null) mListener.onStateChanged(mStates[1]);
return true;
case MotionEvent.ACTION_UP:
Log.e("STATETOUCH", "onTouch: up");
mStateIndex = 2;
if(mListener != null) mListener.onStateChanged(mStates[2]);
return false;
}
return false;
}
}
EDIT in attrs.xml:
and this in attrs.xml
<declare-styleable name="CircleImageView">
<attr name="civ_border_width" format="dimension" />
<attr name="civ_border_color" format="color" />
<attr name="civ_border_overlay" format="boolean" />
<attr name="civ_fill_color" format="color" />
<attr name="state_on" format="boolean" />
<attr name="state_off" format="boolean" />
</declare-styleable>
and use it like this in your code :
<com.yourpackagename.CircleImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:id="#+id/img"
app:civ_border_width="1dp"
app:civ_border_color="#000"
android:src="#drawable/profile_pic"/>
and then in your code do the following:
yourImageView.setOnStateChangedListener(new OnStateChangeListener() {
#Override
public void onStateChanged(int state) {
switch (state){
case R.attr.state_on:
yourImageView.setBorderColor(Color.parseColor("#00ff00"));
break;
case R.attr.state_off:
yourImageView.setBorderColor(Color.parseColor("#ff00ff"));
//do anything you would do after onclick of this imageview here, like open a new activity.
break;
}
Log.e("STATECHANGE", "State changed to: " + context.getResources().getResourceEntryName(state));
}
});
reference : https://stackoverflow.com/a/21969864/2251837
As you can see this code works fine for me. Can you post your code, how you did it, then may be I will be able to help?
EDIT: This is what you need to change in your getView() method :
view.setOnTouchListener(new View.OnTouchListener() { // here view is this view : View view = inflater.inflate(type == List_Section ? R.layout.section : R.layout.listitem, parent, false);
#Override
public boolean onTouch(View v, MotionEvent event) {
small_profile.dispatchTouchEvent(event);
return false;
}
});
You need to draw 2 bitmap here to activate Xfermode:
private Bitmap maskingImage(Bitmap s1, Bitmap s2) {
Bitmap result = Bitmap.createBitmap(s2.getWidth(), s2.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(s1, 0, 0, null);
mCanvas.drawBitmap(s2, 0, 0, paint);
paint.setXfermode(null);
return result;
}
s2 is ur circle, s1 is ur image. If you want to change to Mode.SRC_IN, just swap s1 and s2 param position

Circle ProgressBar

is there anyone that have idea to how create 3 circle progressbar inside each other ? I want something like image below. I tried some but when increase thickness of shape is becomes regtangle !!!
any suggestion ?
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thicknessRatio="11"
android:useLevel="true">
<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep"
android:useLevel="false" />
</shape>
but this is my result :
as you can see the thickness of progressbar is decreased.
and the other is how to set the gray thickness of progressbar same as the colored one !!
Draw a circle like this using java. Create java class CircleImageView and write this piece of code
public class CircleImageView extends AppCompatImageView {
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 2;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
private static final boolean DEFAULT_BORDER_OVERLAY = false;
private final RectF mDrawableRect = new RectF();
private final RectF mBorderRect = new RectF();
private final Matrix mShaderMatrix = new Matrix();
private final Paint mBitmapPaint = new Paint();
private final Paint mBorderPaint = new Paint();
private final Paint mFillPaint = new Paint();
private int mBorderColor = DEFAULT_BORDER_COLOR;
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
private int mFillColor = DEFAULT_FILL_COLOR;
private Bitmap mBitmap;
private BitmapShader mBitmapShader;
private int mBitmapWidth;
private int mBitmapHeight;
private float mDrawableRadius;
private float mBorderRadius;
private ColorFilter mColorFilter;
private boolean mReady;
private boolean mSetupPending;
private boolean mBorderOverlay;
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
a.recycle();
init();
}
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
#Override
public ScaleType getScaleType() {
return SCALE_TYPE;
}
#Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
}
}
#Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (adjustViewBounds) {
throw new IllegalArgumentException("adjustViewBounds not supported.");
}
}
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
if (mFillColor != Color.TRANSPARENT) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
}
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
if (mBorderWidth != 0) {
canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(#ColorInt int borderColor) {
if (borderColor == mBorderColor) {
return;
}
mBorderColor = borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
public void setBorderColorResource(#ColorRes int borderColorRes) {
setBorderColor(getContext().getResources().getColor(borderColorRes));
}
public int getFillColor() {
return mFillColor;
}
public void setFillColor(#ColorInt int fillColor) {
if (fillColor == mFillColor) {
return;
}
mFillColor = fillColor;
mFillPaint.setColor(fillColor);
invalidate();
}
public void setFillColorResource(#ColorRes int fillColorRes) {
setFillColor(getContext().getResources().getColor(fillColorRes));
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth == mBorderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
public boolean isBorderOverlay() {
return mBorderOverlay;
}
public void setBorderOverlay(boolean borderOverlay) {
if (borderOverlay == mBorderOverlay) {
return;
}
mBorderOverlay = borderOverlay;
setup();
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mBitmap = bm;
setup();
}
#Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
mBitmap = getBitmapFromDrawable(drawable);
setup();
}
#Override
public void setImageResource(#DrawableRes int resId) {
super.setImageResource(resId);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
#Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
setup();
}
#Override
public void setColorFilter(ColorFilter cf) {
if (cf == mColorFilter) {
return;
}
mColorFilter = cf;
mBitmapPaint.setColorFilter(mColorFilter);
invalidate();
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void setup() {
if (!mReady) {
mSetupPending = true;
return;
}
if (getWidth() == 0 && getHeight() == 0) {
return;
}
if (mBitmap == null) {
invalidate();
return;
}
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setAntiAlias(true);
mFillPaint.setColor(mFillColor);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(0, 0, getWidth(), getHeight());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay) {
mDrawableRect.inset(mBorderWidth, mBorderWidth);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
updateShaderMatrix();
invalidate();
}
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
}
and use this in your xml like
<com.yourpackagename.CircleImageView
android:id="#+id/profileImg"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center|top"
android:src="#drawable/profile" />
Or else go through this link this is what you are looking for circular progress bar

How remove black background around the circular image view in android

I have created circular image view with the CircularImageView library
and I am facing issues with black background around the circular image in my layout, I tried to resolve this issue but I am failed to fix this issue
Following code is CircularImageView.java file
package de.hdodenhof.circleimageview;
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.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.widget.ImageView;
public class CircleImageView extends ImageView {
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 2;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
private final RectF mDrawableRect = new RectF();
private final RectF mBorderRect = new RectF();
private final Matrix mShaderMatrix = new Matrix();
private final Paint mBitmapPaint = new Paint();
private final Paint mBorderPaint = new Paint();
private int mBorderColor = DEFAULT_BORDER_COLOR;
private int mBorderWidth = DEFAULT_BORDER_WIDTH;
private Bitmap mBitmap;
private BitmapShader mBitmapShader;
private int mBitmapWidth;
private int mBitmapHeight;
private float mDrawableRadius;
private float mBorderRadius;
private ColorFilter mColorFilter;
private boolean mReady;
private boolean mSetupPending;
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);
a.recycle();
init();
}
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
#Override
public ScaleType getScaleType() {
return SCALE_TYPE;
}
#Override
public void setScaleType(ScaleType scaleType) {
if (scaleType != SCALE_TYPE) {
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
}
}
#Override
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (adjustViewBounds) {
throw new IllegalArgumentException("adjustViewBounds not supported.");
}
}
#Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
if (mBorderWidth != 0) {
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(int borderColor) {
if (borderColor == mBorderColor) {
return;
}
mBorderColor = borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth == mBorderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
#Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mBitmap = bm;
setup();
}
#Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
mBitmap = getBitmapFromDrawable(drawable);
setup();
}
#Override
public void setImageResource(int resId) {
super.setImageResource(resId);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
#Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
#Override
public void setColorFilter(ColorFilter cf) {
if (cf == mColorFilter) {
return;
}
mColorFilter = cf;
mBitmapPaint.setColorFilter(mColorFilter);
invalidate();
}
private Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (OutOfMemoryError e) {
return null;
}
}
private void setup() {
if (!mReady) {
mSetupPending = true;
return;
}
if (mBitmap == null) {
return;
}
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
mBorderRect.set(0, 0, getWidth(), getHeight());
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);
mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2);
updateShaderMatrix();
invalidate();
}
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
}
And My layout is
<com.example.util.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
app:border_color="#color/white"
app:border_width="2dp"
android:id="#+id/chooseanavatar"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_marginTop="5dp"
android:layout_gravity="center_horizontal"
android:layout_centerVertical="true"
/>
I think I found a solution in lollipop.
myView = LinearLayout(parent layout for the circleview not the circleview itself)
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
This disable hardware acceleration.
You can use this to circleimageview's parent view, profile_img_container.
Don't use this to circleimageview directly. It willl show you black outer circle.
<LinearLayout
android:id="#+id/profile_img_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax">
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/profile_image"
android:layout_width="96dp"
android:layout_height="96dp"
android:src="#drawable/profile002"
android:layout_marginTop="20dp"
app:civ_border_width="1dp"
app:civ_border_color="#44000000"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax"/>
</LinearLayout>
Source: https://github.com/hdodenhof/CircleImageView/issues/31
circle_imageview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
its working on me. check this link
Came through the same problem with a similar view on 7.0.
Solved by drawing a white canvas before drawing anything else.
#Override
public void onDraw(Canvas canvas) {
canvas.drawARGB(255, 255, 255, 255);
...
}
This workaround has the same visual result as setting a white background directly in the XML, but will not work well if this view is child of a non-flat view (you will see a a white square).
finally got solution ...
this problem resolve after enable hardwareAccelerated in android manifest file.
Add android:hardwareAccelerated="true" to your manifest
After enable this no black area show behind the image while using shapeable image view.
hope your problem resolved ..
Are you using lollipop currently because that problem only appears on lollipop devices,it works fine in pre-lollipop.
Try it with pre-lollipop and if you are using lollipop add this line:
paintBorder.setAlpha(254);
Try changing the background of RelativeLayout of CircleImageView. See below for reference:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="#dimen/base_padding"
android:background="#color/light">
<com.example.util.CircleImageView
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_centerInParent="true"
android:src="#drawable/hugh"
app:border_width="2dp"
app:border_color="#color/dark" />
</RelativeLayout>

Categories

Resources