Drawable is not drawing on canvas - android

I have a custom view and a drawable to be drawn on it, but for some reason the drawable is not drawing itself on the view's canvas. Here's how the drawable is created:
int[] gradientColors=new int[] { 0xFFFF0000,0xFFFFFF00,0xFF00FF00,
0xFF00FFFF,0xFF0000FF,0xFFFF00FF,0xFFFF0000 };
gradient=new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT,
gradientColors);
And here's the onDraw function:
#Override protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
int width=canvas.getWidth();
int height=canvas.getHeight();
gradientBitmap=Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
canvas.setBitmap(gradientBitmap);
gradient.setBounds(0,0,width,height);
gradient.draw(canvas);
}

Try to look at this code it can be helpful for you to learn haw to handle drawing for custom views:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private Rect mRect;
private GradientDrawable mDrawable;
public SampleView(Context context) {
super(context);
setFocusable(true);
mRect = new Rect(0, 0, 220, 120);
/* GradientDrawable.Orientation BL_TR draw the gradient from the bottom-left to the top-right
BOTTOM_TOP draw the gradient from the bottom to the top
BR_TL draw the gradient from the bottom-right to the top-left
LEFT_RIGHT draw the gradient from the left to the right
RIGHT_LEFT draw the gradient from the right to the left
TL_BR draw the gradient from the top-left to the bottom-right
TOP_BOTTOM draw the gradient from the top to the bottom
TR_BL draw the gradient from the top-right to the bottom-left
*/
mDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT,
new int[] { 0xFFFF0000, 0xFF00FF00,
0xFF0000FF });
mDrawable.setShape(GradientDrawable.RECTANGLE);
mDrawable.setGradientRadius((float)(Math.sqrt(2) * 60));
}
static void setCornerRadius(GradientDrawable drawable, float r0,
float r1, float r2, float r3) {
/* setCornerRadii
Specify radii for each of the 4 corners. For each corner,
the array contains 2 values, [X_radius, Y_radius].
The corners are ordered top-left, top-right, bottom-right,
bottom-left
*/
drawable.setCornerRadii(new float[] { r0, r0, r1, r1,
r2, r2, r3, r3 });
}
#Override protected void onDraw(Canvas canvas) {
mDrawable.setBounds(mRect);
float r = 35;
canvas.save();
canvas.translate(10, 10);
mDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
setCornerRadius(mDrawable, r, r, 0, 0);
mDrawable.draw(canvas);
canvas.restore();
canvas.translate(0, mRect.height() + 10);
canvas.save();
canvas.translate(10, 10);
mDrawable.setGradientType(GradientDrawable.RADIAL_GRADIENT);
setCornerRadius(mDrawable, 0, 0, r, r);
mDrawable.draw(canvas);
canvas.restore();
canvas.translate(0, mRect.height() + 10);
canvas.save();
canvas.translate(10, 10);
mDrawable.setGradientType(GradientDrawable.SWEEP_GRADIENT);
setCornerRadius(mDrawable, 0, r, r, 0);
mDrawable.draw(canvas);
canvas.restore();
}
}
}
UPDATE
public class MyView extends View {
private static int measuredWidth = 300;
private static int measuredHeight = 300;
private Rect mRect;
private GradientDrawable mDrawable;
public MyView(Context context) {
super(context);
initializeView();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initializeView();
}
private void initializeView() {
mDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT,
new int[] { 0xFFFF0000,0xFFFFFF00,0xFF00FF00,
0xFF00FFFF,0xFF0000FF,0xFFFF00FF,0xFFFF0000 });
mDrawable.setShape(GradientDrawable.RECTANGLE);
mDrawable.setGradientRadius((float)(Math.sqrt(2) * 60));
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeView();
}
#Override protected void onDraw(Canvas canvas) {
mRect = new Rect(0, 0, measuredWidth, measuredHeight);
mDrawable.setBounds(mRect);
canvas.save();
canvas.translate(10, 10);
mDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
//setCornerRadius(mDrawable, r, r, 0, 0);
mDrawable.draw(canvas);
canvas.restore();
}
I tried this for you it's based on your code and works except that i fixed the height and width:

Related

How to add a imageView in the centre of a customView?

I have a custom view that is a circle. Here is the code for my CircleView:
public class CircleView extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private float angle;
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 40;
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
//Circle color
paint.setColor(Color.RED);
rect = new RectF(strokeWidth, strokeWidth, 1000 + strokeWidth, 1000 + strokeWidth);
//Initial angle is zero
angle = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
} }
and here is how I declare it in the xml layout of an activity:
<com.my_package.ui.recording.CircleView
android:id="#+id/circleView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
All standard stuff. This is how my custom image looks like
Now, I want to place an imageView in the centre on the circleView? Does any one know how can I achieve that?
This is ideally what I would like to end up with:
Thank you in advance.
If you aren't set on using an ImageView and really just want to draw the bitmap in the center then have a look at canvas' drawBitmap method. This will allow you to draw it however/wherever you want.

SweepGradient change position of start and end color

I want to create a CircleView with gradient from bottom -> left -> top -> right.
So I using canvas with SweepGradient like this
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
int[] colors = {Color.GREEN, Color.RED};
float[] positions = {0, 1};
SweepGradient gradient = new SweepGradient(100, 100, colors, positions);
paint.setShader(gradient);
canvas.drawCircle(100, 100, 100, paint);
}
But the default order of this is right -> bottom -> left -> top but I want bottom -> left -> top -> right
I have tried change the positions to
float[] positions = {0.25f, 1.25f};
but it only works in Preview of AndroidStudio, when I run in real device, it displays the result as same as positions = {0, 1}
How can I make SweepGradient gradient from bottom -> left -> top -> right like this
--- UPDATE ---
We can use setLocalMatrix for SweepGradient like this for rotate the gradient
Matrix matrix = new Matrix();
matrix.setRotate(90, 100, 100);
gradient.setLocalMatrix(matrix);
Rotate the canvas before drawing the circle.
public class CircleView extends View {
private Paint paint;
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init() {
paint = new Paint();
int[] colors = {Color.GREEN, Color.RED};
float[] positions = {0, 1};
SweepGradient gradient = new SweepGradient(100, 100, colors, positions);
paint.setShader(gradient);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.rotate(90, 100, 100);
canvas.drawCircle(100, 100, 100, paint);
canvas.restore();
}
}
Edit-1:
Alternative approach suggested by #pkskink is to use setLocalMatrix like below:
public void init() {
int[] colors = {Color.GREEN, Color.RED};
float[] positions = {0, 1};
Matrix matrix = new Matrix();
matrix.postRotate(90, 100, 100);
Shader gradient = new SweepGradient(100, 100, colors, positions);
gradient.setLocalMatrix(matrix);
paint = new Paint();
paint.setShader(gradient);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(100, 100, 100, paint);
}

How to draw gradient or stylish line canvas

This is my activity where i am using to draw the dotted line . but i want to draw gradient or some style in line ..
DragObserverLayout.java
//class for draw line from one place to another
public class DragObserverLayout extends RelativeLayout {
float startX, startY, stopX, stopY;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private List<Rect> lines = new ArrayList<Rect>();
public List<Path> linePath = new ArrayList<Path>();
//class for dragging
public DragObserverLayout(Context context, AttributeSet attrs) {
super(context, attrs);
//setting color stroke and effect
mPaint.setColor(Color.RED);
mPaint.setStyle(Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.BUTT);
mPaint.setPathEffect(new DashPathEffect(new float[] {5,5}, 0));
mPaint.setStrokeWidth(10.0f);
}
//for canvas
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
final int count = lines.size();
for (int i = 0; i < count; i++) {
final Rect r = lines.get(i);
canvas.drawLine(r.left, r.top, r.right, r.bottom, mPaint);
}
}

Drawing text in a custom view, canvas.drawText won't display

I'm trying to draw text in a custom view that has an image as a background. Three things are being drawn.
The bitmap behind the circle
The red circle and
Text over it.
At the moment the circle and bitmap draw perfectly but the text doesn't display.
Code for custom view.
public class NotificationButtonView extends Button
{
private int mNumberOfNotifications = 0;
private Paint mNotificationPaint = new Paint();
private Paint mTextPaint = new Paint();
public NotificationButtonView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public NotificationButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NotificationButtonView(Context context) {
super(context);
}
public void setNotificationNumber(int number)
{
this.mNumberOfNotifications = number;
this.invalidate();
}
public void addNotification()
{
this.mNumberOfNotifications++;
this.invalidate();
}
#Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
mNotificationPaint.setColor(Color.rgb(255,69,0));
mNotificationPaint.setAlpha(220);
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(Color.BLACK);
mTextPaint.setStyle(Style.FILL);
mTextPaint.setTextSize(this.getWidth() / 3);
mTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setLinearText(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int diameter = this.getWidth() / 3;
/*
canvas.drawCircle(
this.getWidth() - diameter,
this.getHeight() - diameter,
diameter,
this.mNotificationPaint
);
*/
//Get the text bounds.
Rect foundBounds = new Rect();
mTextPaint.getTextBounds("1", 0, "1".length(), foundBounds);
foundBounds.offset(0, diameter);
canvas.drawText(
//String.valueOf(mNumberOfNotifications),
"1",
0,
foundBounds.bottom,
this.mTextPaint
);
//For testing the location of the text bounds.
canvas.drawRect(foundBounds, mNotificationPaint);
}
}
You are getting this.getWidth() 0 in onAttachedToWindow() as a result the text size is set to 0.
But you are getting this.getWidth() value in onDraw so in onDraw add this line
mTextPaint.setTextSize(this.getWidth() / 3);

Make Image view rounded (not the image)

Requirement is to:
Req 1 : Fetch images from url
R2: save them in cache
R3: make ImageView rounded not the image
So for R1 & R2 I found a library:
http://loopj.com/android-smart-image-view/
For R3 I've done a lot of R&D , & everything I found converts the image not the ImageView. This is what I've searched:
Mask ImageView with round corner background
How to make an ImageView with rounded corners?
https://github.com/vinc3m1/RoundedImageView
https://github.com/lopspower/CircularImageView
I know it's possible to use the ImageView bitmap & get the image rounded but with the specific library I want to use that isn't possible(maybe possible with very complex threading).
So please help me to get the ImageView rounded not the image.
so this is the minimalistic version:
class RoundImageView extends ImageView {
private static final int RADIUS = 32;
private Paint mPaint;
private Paint mSrcIn;
private RectF mRect;
public RoundImageView(Context context) {
super(context);
// setBackgroundColor(0xffffffff);
mSrcIn = new Paint();
mSrcIn.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRect = new RectF();
}
#Override
public void onDraw(Canvas canvas) {
Drawable dr = getDrawable();
if (dr != null) {
mRect.set(dr.getBounds());
getImageMatrix().mapRect(mRect);
mRect.offset(getPaddingLeft(), getPaddingTop());
int rtc = canvas.saveLayer(mRect, null, Canvas.ALL_SAVE_FLAG);
// draw DST
canvas.drawRoundRect(mRect, RADIUS, RADIUS, mPaint);
canvas.saveLayer(mRect, mSrcIn, Canvas.ALL_SAVE_FLAG);
// draw SRC
super.onDraw(canvas);
canvas.restoreToCount(rtc);
}
}
}
or use even shorter one when hardware acceleration is not used and you can use Canvas.clipPath:
class RoundImageViewClipped extends ImageView {
private static final int RADIUS = 32;
private RectF mRect;
private Path mClip;
public RoundImageViewClipped(Context context) {
super(context);
// setBackgroundColor(0xffffffff);
mRect = new RectF();
mClip = new Path();
}
#Override
public void onDraw(Canvas canvas) {
Drawable dr = getDrawable();
if (dr != null) {
mRect.set(dr.getBounds());
getImageMatrix().mapRect(mRect);
mRect.offset(getPaddingLeft(), getPaddingTop());
mClip.reset();
mClip.addRoundRect(mRect, RADIUS, RADIUS, Direction.CCW);
canvas.clipPath(mClip);
super.onDraw(canvas);
}
}
}
I'm pretty sure you can't "make the ImageView round," since all Views are actually rectangular, so what you're going to have to do is fake it.
Use a method like this to cut a circle from the image:
public Bitmap getRoundedBitmap(Bitmap scaleBitmapImage) {
int targetRadius = scaleBitmapImage.getWidth();
if(targetRadius > scaleBitmapImage.getHeight()) targetRadius = scaleBitmapImage.getHeight();
Bitmap targetBitmap = Bitmap.createBitmap(targetRadius, targetRadius, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
path.addCircle(((float) scaleBitmapImage.getWidth() - 1) / 2, ((float) scaleBitmapImage.getHeight() - 1) / 2, (Math.min(((float) scaleBitmapImage.getWidth()), ((float) scaleBitmapImage.getHeight())) / 2), Path.Direction.CCW);
canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap, new Rect(0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight()), new Rect(0, 0, scaleBitmapImage.getWidth(), scaleBitmapImage.getHeight()), null);
return targetBitmap;
}
Since the clipped part is transparent, it will appear as if the actual View is a circle. Also make sure that the bounds of the View are squared (or that adjustViewBounds="true") else you may get visual distortions in terms of width or height.
Pretty sure that's as close to a "rounded View" as you can actually get.
How about the solution give by Romain Guy to use a custom Drawable. You're ImageView will not be round and your source image will be untouched.
class StreamDrawable extends Drawable {
private final float mCornerRadius;
private final RectF mRect = new RectF();
private final BitmapShader mBitmapShader;
private final Paint mPaint;
private final int mMargin;
StreamDrawable(Bitmap bitmap, float cornerRadius, int margin) {
mCornerRadius = cornerRadius;
mBitmapShader = new BitmapShader(bitmap,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(mBitmapShader);
mMargin = margin;
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(mMargin, mMargin, bounds.width() - mMargin, bounds.height() - mMargin);
}
#Override
public void draw(Canvas canvas) {
canvas.drawRoundRect(mRect, mCornerRadius, mCornerRadius, mPaint);
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
}
You can add rounded corners in a android view with the GradientDrawable.
So ,
GradientDrawable gd = new GradientDrawable();
gd.setColor(Color.TRANSPARENT);
gd.setCornerRadius(15f);
gd.setStroke(1f,Color.BLACK);
yourImageView.setBackground(gd);
SmartImageView extends from ImageView .. so you just have to extend from SmartImageView
Here is a working solution (based on pskink code & smartImageView lib )
Create a new Class
public class RoundedCornersSmartImageView extends SmartImageView{
private int RADIUS = 0;
private RectF mRect;
private Path mClip;
public RoundedCornersSmartImageView(Context context) {
super(context);
init();
}
public RoundedCornersSmartImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedCornersSmartImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
#Override
public void onDraw(Canvas canvas) {
Drawable dr = getDrawable();
if (dr != null) {
mRect.set(dr.getBounds());
getImageMatrix().mapRect(mRect);
mRect.offset(getPaddingLeft(), getPaddingTop());
mClip.reset();
mClip.addRoundRect(mRect, RADIUS, RADIUS, Path.Direction.CCW);
canvas.clipPath(mClip);
super.onDraw(canvas);
}
}
public void setRadius(int radius){
this.RADIUS = radius;
}
private void init(){
mRect = new RectF();
mClip = new Path();
}
}
USAGE
in your layout file your SmartimageView should look like this
<your.package.path.RoundedCornersSmartImageView
android:id="#+id/list_image"
android:layout_width="60dip"
android:layout_height="60dip"
android:src="#drawable/profile_anonyme_thumb"/>
..and init the view in your code this way
RoundedCornersSmartImageView thumb_image=(RoundedCornersSmartImageView) findViewById(R.id.list_image);
thumb_image.setRadius(4);
//SmartImageView methode
thumb_image.setImageUrl(bla.MY_THUMB_URL));
Edit your radius for a round image ..

Categories

Resources