I have a progress bar with text in which I have overridden the onDraw like so:
#Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(textColor);
textPaint.setTextSize(textSize);
Rect bounds = new Rect();
textPaint.getTextBounds(text, 0, text.length(), bounds);
float fx = getX();
float fy = getY();
int x = getWidth() / 2 - bounds.centerX();
int y = getHeight() / 2 - bounds.centerY();
canvas.drawText(text, x, y, textPaint);
}
I am trying to position the text inside of the secondary progress but not really sure how get the the current width of the secondary progress, basically the width of the current progress.
For now I just used a work around, basically I get the percentage of the progress and then multiply it by the density. I needed to align the text 20dp within the progress bar:
#Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(textColor);
textPaint.setTextSize(textSize);
Rect bounds = new Rect();
textPaint.getTextBounds(text, 0, text.length(), bounds);
float density = getContext().getResources().getDisplayMetrics().density;
float percentage = getProgress() / 100.0f;
float x = getWidth() * percentage - (20 * density);
float y = getHeight() / 2 - bounds.centerY();
canvas.drawText(text, x, y, textPaint);
}
Related
So I am nearly at the end.
I have been researching the whole day on how to do this.
Draw a path which grows(animation) from one point to another.
I have tried it with Matrix, but that just ended with turning my whole paths.
Here is a image of my project:
my project
My goal is to draw a animated path from one circle to the other.
Code:
public void init(#Nullable AttributeSet attr) {
circle = new Paint();
circle.setColor(Color.GREEN);
circle.setStyle(Paint.Style.FILL);
circle.setAntiAlias(true);
line = new Paint();
line.setColor(Color.GREEN);
line.setStyle(Paint.Style.STROKE);
line.setStrokeWidth(10);
line.setAntiAlias(true);
Collections.addAll(height, 100, 20, 50, 40, 70, 10, 50); // in percent
System.out.println(height.size() + " this is the size");
}
#Override
protected void onDraw(Canvas canvas) {
float y = getHeight() / 20 * 14;
float x = getWidth() / 8;
float radius = (canvas.getWidth() * canvas.getHeight()) / 40940;
for (int c = 1; c < 8; c++) {
System.out.println("at " + c);
canvas.drawCircle(x * c, y - ((getHeight() / 20) * (height.get(c - 1) / 10)), radius, circle);
points.add(new PointF(x * c, (y - ((getHeight() / 20) * (height.get(c - 1) / 10)))));
}
}
Please Help,
Thanks
you just need animate the path using ValueAnimator
create one path object
Path path = new Path();
and create animator
ValueAnimator animator = new ValueAnimator();
float startX = // starting circle x co-ordinate
float startY = // starting circle y co-ordinate
float endX = // end circle x co-ordinate
float endY = // end circle y co-ordinate
PropertyValuesHolder propertyX = PropertyValuesHolder.ofFloat("x",startX,endX);
PropertyValuesHolder propertyY = PropertyValuesHolder.ofFloat("y",startY,endY);
valueAnimator.setValues(propertyX,propertyY);
valueAnimator.setDuration(1000); // animation time
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float x = (float) animation.getAnimatedValue("x");
float y = (float) animation.getAnimatedValue("y");
path.lineTo(x,y);
invalidate();
}
});
valueAnimator.start();
and in onDraw() draw the path
canvas.drawPath(path,paint);
I am creating custom view, which is like screen below. I can draw views but I am unable to create separate click events for each view. How to set separate click events for each arc view?. Thanks in advance.
Here is the code:
ArcView.java
public class ItemView extends View {
Utils utils;
int left, right, top, bottom;
private int color;
private int start;
private int sweep;
private boolean inner;
private RectF oval;
public float center_x, center_y;
int divOn;
public float radius;
public ItemView(Context context, int color, int start, int sweep) {
super(context);
this.color = color;
this.start = start;
this.sweep = sweep;
utils = Utils.getInstance(getContext());
}
public ItemView(Context context, int color, int start, int sweep, boolean inner, int divOn) {
super(context);
this.color = color;
this.start = start;
this.sweep = sweep;
this.inner = inner;
this.divOn = divOn;
utils = Utils.getInstance(getContext());
}
public RectF getOval() {
return oval;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//There is another flag for inner white circle
if (inner) {
float width = (float) getWidth();
float height = utils.getScreenHeight() - utils.getActionBarSize();
radius = (width - utils.dpTopixel(50)) / divOn;
Path path = new Path();
path.addCircle((width - utils.dpTopixel(50)) / divOn,
(height - utils.dpTopixel(50)) / divOn, radius,
Path.Direction.CW);
Paint paint = new Paint();
paint.setColor(ContextCompat.getColor(getContext(), color));
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
final RectF oval = new RectF();
paint.setStyle(Paint.Style.FILL);
left = -(int) radius;
right = (int) radius;
top = (getHeight() / 2) - (int) radius;
bottom = (getHeight() / 2) + (int) radius;
oval.set(left,
top,
right,
bottom);
canvas.drawArc(oval, start, sweep, true, paint);
} else {
float width = (float) getWidth();
float height = utils.getScreenHeight() - utils.getActionBarSize();
float radius;
radius = (width - utils.dpTopixel(50)) / divOn;
Path path = new Path();
path.addCircle((width - utils.dpTopixel(50)) / 1,
(width - utils.dpTopixel(50)) / 1, radius,
Path.Direction.CW);
Paint paint = new Paint();
paint.setColor(ContextCompat.getColor(getContext(), color));
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
oval = new RectF();
paint.setStyle(Paint.Style.FILL);
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG);
textPaint.setColor(ContextCompat.getColor(getContext(), R.color.white));
textPaint.setTextAlign(Paint.Align.CENTER);
/*Paint.FontMetrics metrics = paint.getFontMetrics();
float textheight = Math.abs(metrics.top - metrics.bottom);
float x = getWidth() / 2;
float y = (getHeight() / 2) + (height / 2);
canvas.drawText("My Text", x, y, paint);*/
left = -(int) radius;
right = (int) radius;
top = (getHeight() / 2) - (int) radius;
bottom = (getHeight() / 2) + (int) radius;
center_x = width / 2;
center_y = utils.getOffset();
int xPos = (getWidth() / 2);
int yPos = (int) ((getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ;
//((textPaint.descent() + textPaint.ascent()) / 2) is the distance from the baseline to the center.
oval.set(left,
top,
right,
bottom);
canvas.drawArc(oval, start, sweep, true, paint);
}
}
}
utils class to detect height and width and convert to px
i want equation to check i click which circle
Create a slice selected listener, override the onTouchEvent in your custom class, calculate which slice the touch event (with the action ACTION_UP) is on using the x,y values. You can then call the function from your slice selected listener and pass details about the selected slice.
I have just begin to create some custom views in Android but I am facing problem while drawing bitmap (arrows) outside the circle.
Here is my code:
Canvas osCanvas = new Canvas(windowFrame); // Create a canvas to draw onto the new image
RectF outerRectangle = new RectF(0, 0, getWidth(), getHeight());
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // Anti alias allows for smooth corners
paint.setColor(Color.parseColor("#FAFAFA")); // This is the color of your activity background
osCanvas.drawRect(outerRectangle, paint);
final Paint stroke = new Paint();
//paint.setColor(Color.TRANSPARENT); // An obvious color to help debugging
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); // A out B http://en.wikipedia.org/wiki/File:Alpha_compositing.svg
float centerX = getWidth() / 2;
float centerY = getHeight() / 2;
double rad = Math.min(getWidth(), getHeight()) / 2.5 - menuInnerPadding;
float radius = (float) rad;
stroke.setColor(Color.parseColor("#999999"));
stroke.setStyle(Paint.Style.STROKE);
stroke.setAntiAlias(true);
stroke.setStrokeWidth(5f);
osCanvas.drawCircle(centerX ,
centerY , radius - stroke.getStrokeWidth() +5f, stroke);
for(int i=0;i<elements.size();i++){
double angle =0;
if(i==0){
angle = startAngle;
}else{
angle = startAngle+(i * ((2 * Math.PI) / elements.size()));
}
elements.get(i).x = (int) (centerX + Math.cos(angle)*(radius));
elements.get(i).y = (int) (centerY + Math.sin(angle)*(radius));
float ang = (float) Math.cos(angle)*(radius);
Path path = new Path();
path.addCircle(elements.get(i).x,elements.get(i).y, radius, Path.Direction.CW);
if(BLINKER_ID == i){
if(blinkerPain != null){
osCanvas.drawBitmap(elements.get(i).bitmap,elements.get(i).x,elements.get(i).y,blinkerPain);
blinkerPain = null;
}
}else{
// here i am drawing the red arrows (bitmap images) But it's not fitting outside the circle.
osCanvas.drawBitmap(elements.get(i).bitmap,elements.get(i).x ,elements.get(i).y ,textPaint);
}
}
Here is my output
I think issue is with the padding.
I did code new write.
You should check this code.
#Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth( 2 );
paint.setStyle(Paint.Style.STROKE );
canvas.drawColor(Color.WHITE);
float x = 400;
float y = 400;
float r = 200;
canvas.drawCircle( x , y , r , paint );
Bitmap icon = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.ic_launcher);
int length = 8;
float radian = (float)(Math.PI * 2f) / length;
for( int i = 0; i<length; i++ ) {
drawBitmap( canvas , icon , x , y , r, radian * i);
}
}
private void drawBitmap( Canvas canvas, Bitmap bitmap, float pivotX, float pivotY, float radius, float radian ) {
Matrix m = new Matrix();
m.postTranslate( -bitmap.getWidth()/2 , -bitmap.getHeight()/2 );
m.postRotate( (float)(radian * 180 / Math.PI) + 90 );
float drawHeight = radius + (bitmap.getHeight()/2);
m.postTranslate( ((float)Math.cos( radian ) * drawHeight) + pivotX
, ((float)Math.sin( radian ) * drawHeight) + pivotY );
canvas.drawBitmap( bitmap , m , null );
}
I made a little loading circle with Canvas and Paint.
This is my first attempt to use these classes so it could be something I used wrong.
My problem is, that the resolution of painting are too low. I can clearly see the pixels.
How could I improve on this?
By the way this is my class:
public class LoadingCircle extends LinearLayout {
public LoadingCircle(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
}
// time
int countDownTime = 180;
Paint paint = new Paint();
RectF oval = new RectF();
Path path = new Path();
// value
int value = 360 / countDownTime;
// starting progress
int progress = -360 - value;
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
float width = (float) getWidth();
float height = (float) getHeight();
float center_x = width / 2, center_y = height / 2;
float loadingRadius = (float) ((width / 2)*0.85);
float whiteRadius = (float) (loadingRadius * 1.06);
float greenRadius = (float) (loadingRadius * 1.14);
// **background green circle**/
oval.set(center_x - greenRadius, center_y - greenRadius, center_x + greenRadius, center_y + greenRadius);
paint.setColor(Color.parseColor("#a3d47b"));
paint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawArc(oval, 270, 360, true, paint);
// ****//
// **background green circle**/
oval.set(center_x - whiteRadius, center_y - whiteRadius, center_x + whiteRadius, center_y + whiteRadius);
paint.setColor(Color.parseColor("#ffffff"));
paint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawArc(oval, 270, 360, true, paint);
// **Loading circle**//
path.addCircle(center_x, center_y, loadingRadius, Path.Direction.CW);
paint.setColor(Color.parseColor("#71b23c"));
paint.setStyle(Paint.Style.FILL_AND_STROKE);
oval.set(center_x - loadingRadius, center_y - loadingRadius, center_x + loadingRadius, center_y + loadingRadius);
progress = progress + value;
Log.i("proges: ", progress + "");
canvas.drawArc(oval, 270, progress, true, paint);
// /**//
}
public void setCountDownTime(int time) {
this.countDownTime = time;
this.value = 360 / countDownTime;
this.progress = -360 - value;
}
// reseting loading circle
public void reset() {
this.progress = -360 - value;
this.invalidate();
}
}
Declare paint like this:
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
This will enable the antialiasing and you'll get rid of that ugly pixellation.
Or, you can do it in your function:
paint.setAntiAlias(true);
I draw an arc using onDraw(canvas):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
}
public class MyView extends View {
public MyView(Context context) {
super(context);
}
#Override
public void onDraw(Сanvas canvas) {
super.onDraw(canvas);
float width = (float) getWidth();
float height = (float) getHeight();
float radius;
if (width > height) {
radius = height / 4;
} else {
radius = width / 4;
}
final Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStrokeWidth(50);
paint.setStyle(Paint.Style.STROKE);
float center_x, center_y;
center_x = width / 2;
center_y = height / 4;
final RectF oval = new RectF();
oval.set(center_x - radius, center_y - radius, center_x + radius,
center_y + radius);
paint.setStyle(Paint.Style.STROKE);
center_x = width / 2;
center_y = height * 3 / 4;
oval.set(center_x - radius, center_y - radius, center_x + radius,
center_y + radius);
canvas.drawArc(oval, -90, 45, false, paint);
}
}
Tell me, how to dynamically change the value of sweepAngle() == 45 in line
canvas.drawArc(oval, -90, 45, false, paint)?
One solution would be to have a sweepAngle field in your class, and use that instead of 45 in drawing the arc. Then have a timer that periodically adds to sweepAngle and redraws the canvas.