How to refresh background color in onDraw - android

This is the most simplified version of my view.
public class MyView extends View {
private int mBackgroundColor = android.R.color.white;
#Override
public void setBackgroundColor(int color) {
super.setBackgroundColor(color);
mBackgroundColor = color;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(mBackgroundColor);]
//canvas.drawColor(mBackgroundColor, Mode.CLEAR);
//canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint);
}
}
the problem is the background color does not change when the setBackgroundColor is called from the activity. i guess i'am not seeing the obvious.
SOLVED:
took hint from nmJohn about clipRect
//Clear the screen
canvas.clipRect(0, 0, viewWidth, viewHeight, Region.Op.REPLACE);
mPaint.setColor(mBackgroundColor);
canvas.drawRect(0, 0, viewWidth, viewHeight, mPaint);
//Draw the image
canvas.clipRect(mRectDst.left, mRectDst.top, mRectDst.right, mRectDst.bottom, Region.Op.REPLACE);
canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint);
one more hint for the future seekers
please make sure that android.graphics.Color i.e hex format is supplied rather that android.R.color.[White/Black/..] took be unaware for a while.

drawColor just sets the background color of the current clip. Try setting clipRect to the area of the canvas.
Also, make sure your view is actually getting invalidated, otherwise onDraw will not get called.

Related

Canvas.drawRect is not work in TextView's onDraw when set gravity

I have a custom view extends form TextView,and write some code in onDraw():
#Override
protected void onDraw(Canvas canvas) {
if (mTextShader == null) {
createShader();
}
shaderMatrix.setTranslate(mProgressWidth,0);
mTextShader.setLocalMatrix(shaderMatrix);
Paint paint = new Paint();
paint.setShader(mBgShader);
canvas.drawRect(0,0,mProgressWidth,getBottom(),paint);
getPaint().setShader(mTextShader);
super.onDraw(canvas);
}
It looks like this:
enter image description here
Just set some shader,and draw a rect,it works fine if I don't use
android:gravity="center"
and
android:singleLine="true"
together,(just one of them is pretty good,)
if only use this property,these shaders and rect are gone!
why?
Before you draw in the canvas, translate the scrolled XY distance
canvas.translate(getScrollX(), getScrollY());
canvas.drawRect(0,0, getWidth(), getHeight(), borderPaint);
your super.onDraw(canvas); should be first line otherwise parent will paint on top of your drawing. also call this setWillNotDraw(false) in your constructor.

Custom Vertical Progressbar in Android

I need to achieve a custom vertical Progressbar like the one shown in the image below. It must have a circle at the beginning and an arrow at the end.
What would be the best way to achieve this? I'm not a design expert, so I don't know if it would be easier by using a 9png file or creating my own drawable class or another options.
I have tried with the following repo https://github.com/halzhang/Android-VerticalProgressBar, but this only rotates the ProgressBar, it cannot apply a custom view like I need.
Finally, I have created a custom view extending from View class and I've overriden onDraw method, drawing a Line, a Circle and a Triangle.
Check the following code:
#Override
protected synchronized void onDraw(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(getResources().getColor(R.color.grey_300));
mPaint.setStrokeWidth(STROKE_WIDTH);
mPaint.setAntiAlias(true);
canvas.drawLine(centerX, MARGIN, centerX, getHeight() - MARGIN, mPaint);
canvas.drawCircle(centerX, MARGIN, STROKE_WIDTH, mPaint);
mPath.reset();
mPath.moveTo(0, STROKE_WIDTH * 2);
mPath.lineTo(-STROKE_WIDTH, 0);
mPath.lineTo(STROKE_WIDTH, 0);
mPath.close();
mPath.offset(centerX, getHeight() - TOP_BOTTOM_MARGIN - STROKE_WIDTH);
canvas.drawPath(mPath, mPaint);
}

Animating ActionBar's icon

I have an ActionBar icon (the main one on the left, not an action item) that I would like to animate.
I am setting my ActionBar's icon in my Activity like this:
getSupportActionBar().setIcon(icon)
where icon is a Drawable produced by a library that converts a custom XML view into a bitmap. This XML view is a RelativeLayout with a background image and a TextView on top.
Today, when I have to update the TextView I simply re-generate the icon and call setIcon again. Instead, I would like to get a hold of my TextView and apply some animation effect on it, like fade-out and then fade-in after updating it (maybe never having to call setIcon, just re-use the same one).
Not sure how to go about this. Can someone recommend an approach?
EDIT: trying this approach:
In MyActivity:
Drawable myDrawable = new MyDrawable();
supportActionBar.setIcon(myDrawable);
and:
public class MyDrawable extends Drawable {
private Paint paint;
private RectF rect;
public MyDrawable() {
this.paint = new Paint();
this.rect = new RectF();
}
#Override
public void draw(Canvas canvas) {
paint.setARGB(255, 0, 255, 0);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
rect.right = 20f;
rect.bottom = 20f;
canvas.drawRoundRect(rect, 0.5f, 0.5f, paint);
}
#Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}
Nothing shows up. I verified that onDraw gets called. Something suspicious to me is that canvas has both height & width set to 1.
A proper approach for it would be to forget the XML layout and create a custom Drawable.
An instance of this custom drawable will be set to the icon on the ActionBar and call invalidateSelf() whenever necessary to redraw (due to animation, for example).
The drawable can hold reference to other drawables (e.g. BitmapDrawable to have something from the /res/ folder or a Color or Gradient drawable for a background shade) and call (for example) bgDraw.draw(canvas) during the onDraw callback.
It can also draw stuff directly on the canvas that is given to it during onDraw callback. With the canvas you can draw circle, lines, areas, path and text directly on it.
edit:
very simple animation example (didn't check the code, likely typos):
private long animationTime;
public void doAnimation(){
animationTime = System.currentTimeMilis() + 3000; // 3 seconds
invalidateSelf();
}
public void onDraw(Canvas canvas){
// do your drawing.
// You can use difference between
// currentTimeMilis and animationTime for status/position
...
// at the end
if(animationTime > System.currentTimeMilis())
invalidateSelf();
}

How do i clean drawn path on canvas in android

i need some help on my android project.
i have a canvas and i fill it with some bitmap.
and i have a pointer that drawn a line on the canvas.
my problem is how to clean the line that i've drawn before?
what method should i call on canvas?
i've tried Canvas.drawColor(), invalidate() and that's not working.
and what is the function of Canvas.drawColor() and
Please help me solve my problem.
thanks in advance
UPDATE!
if i made the code like this:
#Override
protected void onDraw(Canvas canvas) {
// fills the canvas with black
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, p);
obaby.draw(canvas);
}
where i place invalidate() in my code?
and what code should i use if i want to clear the canvas using a button?
UPDATE!
i wrote my onDraw like this:
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
if(letsdraw){
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, p);
obaby.draw(canvas);
}
}
and the method in reset button is like this:
public void rst(){
letsdraw = false;
invalidate();
Log.v("tag", "this method called");
}
but no change in the canvas when i called the method.
did i wrote something wrong on the code above?
Make your logic like this. Draw the line on the Canvas with some condition. Check if you want to draw the line, then draw the line.
Skeleton code -
#Override
protected void onDraw(Canvas canvas)
{
if(needToDrawLine)
{
//draw the line
}
// Other drawing stuff
}
Now just update your needToDrawLine variable and call invalidate(). You'll get your result. Let me know if it works.
Update:
onDraw() method will call everytime you call the invalidate(). So everyting inside the onDraw() will execute. The way is, you have to prevent it from drawing some of the part. You'll call invalidate() when you want to redraw the whole view, for example - button for clear the canvas.
canvas.drawColor(Color.BLACK); this line clear your whole view to BLACK color.
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); this line draw the bitmap at (0,0).
canvas.drawPath(mPath, p); this line draw the path mPath.
obaby.draw(canvas); some other object draw itself.
Now - for example you want to clear the screen, when button pressed. Just initialize a variable if it draw everything. And update the variable in button click.
public boolean drawEverything = true;
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
if(drawEverything)
{
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, p);
obaby.draw(canvas);
}
}
public void buttonClicked( ... )
{
drawEverything = false;
}
Iam useing this errage the paint in my activity
mBitmap.eraseColor(Color.TRANSPARENT);
mPath.reset();
mView.invalidate();

Android graphics outside of onDraw method

Okay, so I'm trying to draw to a canvas on Android from outside of the onDraw method.
It's just easiest to show my code:
public class TestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Paint p = new Paint();
p.setColor(Color.GREEN);
Panel a = new Panel(this,150,150,50,p);
a.drawThing();
setContentView(a);
}
class Panel extends View{
private float radius, x, y;
private Canvas CAN;
private Paint p;
public Panel(Context context, float x, float y, float radius, Paint p){
super(context);
this.x = x;
this.y = y;
this.radius = radius;
this.p = p;
}
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
CAN = canvas;
}
public void drawThing(){
CAN.drawCircle(x, y, radius, p);
}
}
}
Do you see what I'm trying to do? But for some reason it throws a NullPointerException
Many of the graphics resources are explicitly freed/released after they've been used. I'm not exactly sure why they do this, but whatever the reason, they don't you to do what you're trying.
Instead of drawing outside of the onDraw method, use some kind of flag to change what the onDraw method is doing. When you want to draw some specific thing, you can set the right flag, and call invalidate().
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
if (doThing) {
canvas.drawCircle(x, y, radius, p);
}
}
EDIT
Something else to consider is drawing to and "off-scrren" source. This means using some kind of graphics representation like a bitmap as a buffer that you can draw to in other code. This won't update your gui, but it will give you the chance to do some heavy duty drawing without locking up the user's device. Once you are done drawing to the bitmap (or whatever) you can invalidate your view and draw it to the screen in the onDraw(Canvas) method.
I'm pretty sure that the null pointer happens because you're calling drawSomething before onDraw ever gets called. So CAN is null.
You can draw onto canvas outside of the onDraw. See this Can we have two canvases in an activity ? (OR) Having a canvas outside the onDraw() is not working for more info.

Categories

Resources