How can I make move in coordinates Y, a canvas.drawCircle?
I want to make the sensation like the circle fall where I touch on the screen but I don't know how to animate it.
My onDraw:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
anchoX = x;
anchoY = y;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
canvas.drawPaint(paint);
/*Texto*/
paint.setColor(Color.BLACK);
paint.setTextSize(80);
canvas.drawText("CONECTA 4", 70, 130, paint);
/*Separador*/
paint.setColor(Color.parseColor("#5C5C5C"));
canvas.drawRect(0, 200, 600, 210, paint);
/*Tablero*/
int radius = 25;
for (int i = 0; i < Game.NFILAS; i++)
for (int j = 0; j < Game.NCOLUMNAS; j++){
if (game.estaVacio(i,j)){
color = Color.WHITE;
paint.setColor(color);
canvas.drawCircle(getPixelFromColumna(j), getPixelFromFila(i), radius, paint);
} else if (game.estaJugador(i,j)){
paint.setColor(coloreado);
canvas.drawCircle(getPixelFromColumna(j), getPixelFromFila(i), radius, paint);
} else {
color = Color.RED;
paint.setColor(color);
canvas.drawCircle(getPixelFromColumna(j),getPixelFromFila(i), radius, paint);
}
}
}
you can check this answer. This is what you were looking for draw a circle with animation
For creating the circle you can you java file like this
public class Circle extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private float angle;
public Circle(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);
//size 200x200 example
rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth);
//Initial Angle (optional, it can be zero)
angle = 120;
}
#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 for creating animation
public class CircleAngleAnimation extends Animation {
private Circle circle;
private float oldAngle;
private float newAngle;
public CircleAngleAnimation(Circle circle, int newAngle) {
this.oldAngle = circle.getAngle();
this.newAngle = newAngle;
this.circle = circle;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation transformation) {
float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);
circle.setAngle(angle);
circle.requestLayout();
}
}
and you can use like this in xml for defining
<com.package.Circle
android:id="#+id/circle"
android:layout_width="300dp"
android:layout_height="300dp" />
Animate you circle by using this sample code
Circle circle = (Circle) findViewById(R.id.circle);
CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
animation.setDuration(1000);
circle.startAnimation(animation);
Related
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.
I need to implement curved text which draw text on circular path on canvas.
It does draw circular path using
canvas.drawTextOnPath(QUOTE, circle, 485, 20, tPaint);
but it is not working for different length of the text.
Following is my Class to draw circular text on the canavs.
public class CircularTextVie extends View {
private String QUOTE = "";
private Path circle;
private Paint cPaint;
private Paint tPaint;
public CircularTextVie(Context context) {
super(context);
circle = new Path();
cPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
cPaint.setStyle(Paint.Style.STROKE);
cPaint.setColor(Color.LTGRAY);
cPaint.setStrokeWidth(3);
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.restore();
int xPos = (canvas.getWidth() /3);
int yPos = (int) ((canvas.getHeight() / 3) - ((tPaint.descent() + tPaint.ascent()) / 3)) ;
circle.addCircle(xPos, yPos, 150, Path.Direction.CW);
canvas.drawTextOnPath(QUOTE, circle, 485, 20, tPaint);
QUOTE="";
}
public void SetText(String text) {
this.QUOTE = text;
}
public void SetTypeFace(Typeface face) {
cPaint.setTypeface(face);
tPaint.setTypeface(face);
}
public void SetColor(int color) {
cPaint.setColor(color);
tPaint.setColor(color);
}
}
Thanks.
This can be done by varying the x and y positions based on textwidth
Define variables
private Rect textBounds;
private int mTextWidth, mTextHeight,centerX,centerY;
Add the below in the constructor of customview
textBounds = new Rect();
tPaint.getTextBounds(QUOTE, 0, QUOTE.length(), textBounds);
mTextWidth = Math.round(tPaint.measureText(QUOTE.toString())); // Use measureText to calculate width
mTextHeight = textBounds.height(); // Use height from getTextBounds()
Then in onDraw
canvas.drawCircle(centerX,centerY,150,mCirlcePaint);
circle.addCircle(centerX, centerY, 150, Path.Direction.CW);
// Note the 0 that's y offset. textdraw at circumference of the circle. Changing y you probably need to change the radius as well i guess.
canvas.drawTextOnPath(QUOTE, circle, (centerX)-(mTextWidth / 2f), 0, tPaint);
centerX,centerY are the center of the circle ie canvaswidht/2 and canvasHeight/2. I drew a circle for reference
The results for hello
The result for a bigger text
For numbers
Edit: To the question in comment
The math involved is in calculating the semi circle using text length
radius = (float) ((mTextWidth) / (Math.PI)). If text length is greater than your canvas you need to reduce the text size or use the full circle radius = (float) ((mTextWidth) / (2*(Math.PI))). Few other edge case you can consider to draw the text properly.
public class GraphicsView extends View {
private String QUOTE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Path circle;
private Paint mCirlcePaint;
private Paint tPaint;
private Rect textBounds;
private int mTextWidth, mTextHeight, centerX, centerY;
private float radius;
public GraphicsView(Context context) {
super(context);
circle = new Path();
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
tPaint.setTextSize(100f);
textBounds = new Rect();
tPaint.getTextBounds(QUOTE, 0, QUOTE.length(), textBounds);
mTextWidth = Math.round(tPaint.measureText(QUOTE.toString())); // Use measureText to calculate width
mTextHeight = textBounds.height(); // Use height from getTextBounds()
mCirlcePaint = new Paint();
mCirlcePaint.setStyle(Paint.Style.FILL);
mCirlcePaint.setColor(Color.GREEN);
radius = (float) ((mTextWidth) / (Math.PI));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerX = w / 2;
centerY = h / 2;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.rotate(180, getWidth() / 2, getHeight() / 2);
canvas.drawCircle(centerX, centerY, radius, mCirlcePaint);
circle.addCircle(centerX, centerY, radius, Path.Direction.CW);
canvas.drawTextOnPath(QUOTE, circle, 0, 0, tPaint);
}
}
I need to make something like this:
I'd try to draw this using Canvas.drawArc(...) but I failed.
Can anyone help me?
I created a view that can draw the shape that you want.
It starts by creating a path for one of the quarters, and rotating the canvas by 90 degrees to draw the path 4 times. The Paint used to draw the Path is determined by the progress / maxProgress.
I used a second path to denote the region of the canvas to clip out when drawing, so that there are empty spaces between the quarters.
Finally, the text can be drawn in the middle after restoring the canvas rotation and clipping.
public class CustomProgressView extends View {
private int progress;
private int maxProgress;
private float arcWidth;
private float arcPadding;
private Paint paintPositive;
private Paint paintNegative;
private Paint paintText;
private Path path;
private Path clipPath;
private ProgressListener listener;
public CustomProgressView(Context context) {
super(context);
init();
}
public CustomProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
arcWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, getResources().getDisplayMetrics());
arcPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, getResources().getDisplayMetrics());
paintPositive = new Paint();
paintPositive.setColor(Color.RED);
paintPositive.setStyle(Paint.Style.FILL_AND_STROKE);
paintPositive.setAntiAlias(true);
paintNegative = new Paint();
paintNegative.setColor(Color.BLUE);
paintPositive.setStyle(Paint.Style.FILL_AND_STROKE);
paintNegative.setAntiAlias(true);
paintText = new Paint();
paintText.setColor(Color.BLACK);
paintText.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 24, getResources().getDisplayMetrics()));
progress = 0;
maxProgress = 10;
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
float diameter = Math.min(getWidth(), getHeight());
RectF ovalOuter = new RectF(0, 0, diameter, diameter);
RectF ovalInner = new RectF(ovalOuter.left + arcWidth, ovalOuter.top + arcWidth, ovalOuter.right - arcWidth, ovalOuter.bottom - arcWidth);
path = new Path();
path.moveTo(ovalOuter.centerX(), ovalOuter.top);
path.addArc(ovalOuter, 270, 90);
path.lineTo(ovalInner.right, ovalInner.centerY());
path.addArc(ovalInner, 0, -90);
path.lineTo(ovalOuter.centerX(), ovalOuter.top);
clipPath = new Path();
clipPath.addRect(ovalOuter.left, ovalOuter.centerY() - arcPadding / 2, ovalOuter.right, ovalOuter.centerY() + arcPadding / 2, Path.Direction.CW);
clipPath.addRect(ovalOuter.centerX() - arcPadding / 2, ovalOuter.top, ovalOuter.centerX() + arcPadding / 2, ovalOuter.bottom, Path.Direction.CW);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float perc = (float) progress / (float) maxProgress;
int state = 0;
if (perc < 0.25) {
state = 1;
} else if (perc < 0.5) {
state = 2;
} else if (perc < 0.75) {
state = 3;
} else {
state = 4;
}
RectF bounds = new RectF();
path.computeBounds(bounds, true);
// Draw Circle
canvas.save();
// Clip padding
canvas.clipPath(clipPath, Region.Op.DIFFERENCE);
canvas.drawPath(path, state == 1 ? paintPositive : paintNegative);
canvas.rotate(90, bounds.left, bounds.bottom);
canvas.drawPath(path, state == 2 ? paintPositive : paintNegative);
canvas.rotate(90, bounds.left, bounds.bottom);
canvas.drawPath(path, state == 3 ? paintPositive : paintNegative);
canvas.rotate(90, bounds.left, bounds.bottom);
canvas.drawPath(path, state == 4 ? paintPositive : paintNegative);
canvas.restore();
// Draw Progress
String text = String.valueOf(progress);
Rect textBounds = new Rect();
paintText.getTextBounds(text, 0, text.length(), textBounds);
float x = bounds.left - textBounds.width() / 2;
float y = bounds.bottom + textBounds.height() / 2;
canvas.drawText(text, x, y, paintText);
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
int oldProgress = this.progress;
this.progress = progress;
if (listener != null) {
listener.onProgressChanged(oldProgress, progress);
}
invalidate();
}
public int getMaxProgress() {
return maxProgress;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
invalidate();
}
public ProgressListener getListener() {
return listener;
}
public void setListener(ProgressListener listener) {
this.listener = listener;
}
public interface ProgressListener {
void onProgressChanged(int oldProgress, int newProgress);
}
}
I would like to draw a rectangle on an ImageView as a picture below (black border and transparent as background).
Basically I download an Image, put in in a ImageView and after I receive 4 points to draw a rectangle.
Thanks in advance
Your problem for android.view.InflateException can be solved by deleting the constructors from DrawView class and auto generate them again. Now for the rectangle you have to have the onDraw similar like this:
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.FILL);
float leftx = 50;
float topy = 50;
float rightx = 150;
float bottomy = 150;
// FILL
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
paint.setStrokeWidth(10);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
// BORDER
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
}
If you want to get the coordinates on click an then draw the rectangle override the onTouchEvent method and do something like this
class DrawView extends ImageView {
float x, y;
float width = 60.0f;
float height = 50.0f;
boolean touched = false;
public DrawView(Context context) {
super(context);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (touched) {
Paint paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.FILL);
// FILL
canvas.drawRect(x, y, (x + width) / 0.5f, (y + height) / 0.5f, paint);
paint.setStrokeWidth(10);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
// BORDER
canvas.drawRect(x, y, (x + width) / 0.5f, (y + height) / 0.5f, paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
touched = true;
//getting the touched x and y position
x = event.getX();
y = event.getY();
invalidate();
return true;
}
}
I solved my problem in thanks the help of #vasilis.
I created:
class DrawView extends ImageView {
private int numberOfRectangles=0;
private ArrayList<Rectangles> listRect;
public DrawView(Context context) {
super(context);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (numberOfRectangles> 0 && listRect!= null)
{
for (int i=0; i< numberOfRectangles; i++)
{
Paint paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setStyle(Paint.Style.FILL);
float leftx = listRect.get(i).getLeftx();
float topy = listRect.get(i).getTopy();
float rightx = listRect.get(i).getRightx();
float bottomy = listRect.get(i).getBottomy();
// FILL
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
paint.setStrokeWidth(10);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
// BORDER
canvas.drawRect(leftx, topy, rightx, bottomy, paint);
}
}
}
public void creatRectangles(ArrayList<Rectangles> arrayRettangoliTest) {
numberOfRectangles=arrayRettangoliTest.size();
this.listRect= arrayRettangoliTest;
this.invalidate();
}
}
in my xml file:
<it.path.DrawView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/placeholder" />
I create a Class Rectangles:
public class Rectangles {
private float leftx;
private float topy ;
private float rightx;
private float bottomy;
public Rectangles(float leftx, float topy, float rightx, float bottomy) {
this.leftx = leftx;
this.topy = topy;
this.rightx = rightx;
this.bottomy = bottomy;
}
#Override
public String toString() {
return "Rectangles{" +
"leftx=" + leftx +
", topy=" + topy +
", rightx=" + rightx +
", bottomy=" + bottomy +
'}';
}
public void setLeftx(float leftx) {
this.leftx = leftx;
}
public void setTopy(float topy) {
this.topy = topy;
}
public void setRightx(float rightx) {
this.rightx = rightx;
}
public void setBottomy(float bottomy) {
this.bottomy = bottomy;
}
public float getLeftx() {
return leftx;
}
public float getTopy() {
return topy;
}
public float getRightx() {
return rightx;
}
public float getBottomy() {
return bottomy;
}
}
And in my MainActivity (ex after an onClick()):
...
ArrayList<Rectangles> arrayRectanglesTest= new ArrayList<>(4);
arrayRectanglesTest.add(new Rectangles(50, 50, 100, 100));
arrayRectanglesTest.add(new Rectangles(150, 150, 200, 200));
arrayRectanglesTest.add(new Rectangles(250, 250, 300, 300));
arrayRectanglesTest.add(new Rectangles(350, 350, 400, 400));
arrayRectanglesTest.add(new Rectangles(450, 450, 500, 500));
imageView.creatRectangles(arrayRectanglesTest);
...
So I made dynamic the number of rectangles
here the Result
I have the following oval GradientDrawable created programmatically to display a circle:
GradientDrawable drawable = new GradientDrawable();
drawable.setColor(Color.TRANSPARENT);
drawable.setShape(GradientDrawable.OVAL);
drawable.setStroke(wheelStrokeWidth, Color.parseColor(WHEEL_STROKE_COLOR));
drawable.setSize(2*wheelRadius+wheelStrokeWidth,2*wheelRadius+wheelStrokeWidth);
ImageView iv = new ImageView(activity);
iv.setImageDrawable(drawable);
I would like to animate the drawing of this circle, to make it draw progressively. First it's just an arc of 0°, then 1°, then progressively it goes to a full 360° circle (sorry if I'm not clear, have trouble to express it in English).
Anyone has an idea on how to do that?
Thank you!
This is not a perfect solution. but this may give you some Idea.
public class MyView extends View {
private Bitmap mBitmap;
private Paint mPaint;
private RectF mOval;
private float mAngle = 135;
private Paint mTextPaint;
public MyView(Context context) {
super(context);
// use your bitmap insted of R.drawable.ic_launcher
mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.image1);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOval = new RectF();
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(48);
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setColor(0xffffaa00);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Matrix matrix = new Matrix();
RectF src = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
RectF dst = new RectF(0, 0, w, h);
matrix.setRectToRect(src, dst, ScaleToFit.CENTER);
Shader shader = new BitmapShader(mBitmap, TileMode.CLAMP,
TileMode.CLAMP);
shader.setLocalMatrix(matrix);
mPaint.setShader(shader);
matrix.mapRect(mOval, src);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xff0000aa);
canvas.drawArc(mOval, -90, mAngle, true, mPaint);
canvas.drawText("click me", getWidth() / 2, getHeight() / 2,
mTextPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float w2 = getWidth() / 2f;
float h2 = getHeight() / 2f;
mAngle = (float) Math.toDegrees(Math.atan2(event.getY() - h2,
event.getX() - w2));
mAngle += 90 + 360;
mAngle %= 360;
if (mAngle == 0) {
mAngle = 360;
}
invalidate();
return true;
}
}
And Credit goes to some other user. He posted this solution at some where (I forgot) and I used that...
By following the idea on this post: Android custom Animation for an ArcShape, I changed my GradientDrawable to a custom View, and made this class to draw progressively an arc:
/**
* An arc with an animation to draw it progressively
*
* Usage:
*
* AnimatedArc aa = new AnimatedArc(...)
* AnimatedArc.ProgressiveDrawing animation = aa.getAnimation(...)
* aa.startAnimation(animation)
*/
public class AnimatedArc extends View {
int delta, startAngle, sweepAngle, currentSweepAngle;
Paint p = new Paint();
Rect rect = new Rect();
RectF rectF = new RectF();
public AnimatedArc(Context context, int strokeWidth, String color, int startAngle, int sweepAngle, boolean doNotAnimate) {
super(context);
p.setAntiAlias(true);
p.setColor(Color.parseColor(color));
p.setStyle(Paint.Style.STROKE);
p.setStrokeWidth(strokeWidth);
delta = strokeWidth / 2;
this.startAngle = startAngle;
this.sweepAngle = sweepAngle;
this.currentSweepAngle = doNotAnimate ? sweepAngle : 0;
}
public ProgressiveDrawing getAnimation(int duration) {
return new ProgressiveDrawing(duration);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.getClipBounds(rect);
rectF.set(rect.left+delta, rect.top+delta, rect.right-delta, rect.bottom-delta);
canvas.drawArc(rectF, startAngle, currentSweepAngle, false, p);
}
public class ProgressiveDrawing extends Animation {
public ProgressiveDrawing(int duration) {
setDuration(duration);
setInterpolator(new LinearInterpolator());
}
public ProgressiveDrawing(int duration, Interpolator interpolator) {
setDuration(duration);
setInterpolator(interpolator);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
currentSweepAngle = (int) (sweepAngle * interpolatedTime);
postInvalidate();
}
}
}