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);
}
Related
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.
I need a progress bar displaying progress from right to left or from left to right depending on variable. I have also text in the middle of the bar. For all that, I am using a custom class. For rotating the bar, I followed this thread but somehow either the text is not displayed, or it is rotated, or everything disappears from the view...
Code without rotation:
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw text
}
I have a property positive telling whether to start from left or from right. It would be easy, if I didn't had the text, I would simply call setRotation() somewhere in the code, but now I am trying to rotate the canvas and I can't manage it to bring everything in the correct order. Can someone help me?
I just found it out. Using this thread, I ended up with the following code:
protected synchronized void onDraw(Canvas canvas) {
canvas.save();
if(!positive) {
int cx = this.getMeasuredWidth() / 2;
int cy = this.getMeasuredHeight() / 2;
canvas.scale(-1f, 1f, cx, cy);
}
super.onDraw(canvas);
canvas.restore();
// draw text
}
I have no idea why rotation doesn't work for me but the scale method works fine.
I would like to send each time different Drawable shape to view and then add it to my activity.
The problem is I can't find a way to add the drawable shape into the canvas when I'm overriding the onDraw method.
The design supposed to be reusable, I can draw rect first and then draw circle...
I want to find a way to send the view different shape. Is it possible?
#Override
protected void onDraw(Canvas canvas) {
// Draw the ball
ballBounds.set(ballX-ballRadius, ballY-ballRadius, ballX+ballRadius, ballY+ballRadius);
paint.setColor(Color.GREEN);
// canvas.drawOval(ballBounds, paint);
canvas.drawRect(ballBounds, paint);
}
Although, your question needs more explanation on what you need, but with what I could understand is you want rect, or circle on desire, here it is,
Add, global variable int ShapeStructure = 0;
#Override
protected void onDraw(Canvas canvas)
{
// Draw the ball
ballBounds.set(ballX-ballRadius, ballY-ballRadius, ballX+ballRadius, ballY+ballRadius);
paint.setColor(Color.GREEN);
if(ShapeStructure == 0){
canvas.drawOval(ballBounds, paint);
}else{
canvas.drawRect(ballBounds, paint);
}
}
Now that, you have a variable at your disposal, you can control what you want to paint.
Hope, this helps, let me know if you want something else.
I'm extending LinearLayout:
public class MyLinearLayout extends LinearLayout {
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(0xFFFF0000);
canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
}
}
If the layout has child elements, shouldn't the red line above be drawn on top of them? Considering a layout like:
<MyLinearLayout>
<ImageView />
</MyLinearLayout>
I'd expect to get the red line drawn above the child ImageView. But it gets drawn below it. I was assuming all child drawing would have been completed after the super.onDraw() line is finished.
Is there a way to get to the canvas and draw something on it after all child drawing has been completed?
Thanks
Layouts don't draw unless you call setWillNotDraw(false);. They do that for efficiency reasons.
EDIT:
onDraw() really is meant to just allow you to modify the Canvas before the drawing operation happens. It doesn't actually draw. What you want to do is override draw() like so:
#Override
protected void draw(Canvas canvas) {
super.draw(canvas);
Paint paint = new Paint();
paint.setColor(0xFFFF0000);
canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
}
Calling the super will draw all the children in the view. Then it will draw all the lines. I do still believe you need setWillNotDraw(false) to be called though.
I'm rewriting my answer as I hadn't seen your line of code where you were drawing to the canvas.
The canvas like some other graphics environments is inverted. So calling getHeight() is actually drawing the line at the bottom. Instead call
canvas.drawLine( 0, 0, getWidth(), 0, paint);
This means draw the line at the top, across the width of the view.
Also, calling super first paints the children prior to any custom painting so your fine there.
If you have a LinearLayout and you need:
draw all of its children first, like buttons, image views
then, on top of those components, draw something directly on the canvas.
You can try this:
public class YourClass extends LinearLayout
{
#Override
protected void dispatchDraw(Canvas canvas)
{
super.dispatchDraw(canvas);
// do your custom drawings afterwards
canvas.drawCircle...
canvas.drawLine...
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.