The following is supposed to draw an axis in the middle of the screen. However, nothing appears. I am positive that is has to do with my Paths.
#Override
protected void onDraw(Canvas canvas) {
//Variables declared here temporarily for testing purposes
int canterX = getWidth() /2;
int centerY = getHeight() /2;
int radius = 150;
Path verticalAxis = new Path();
Path horizontalAxis = new Path();
drawAxis();
}
private void drawAxis(Canvas canvas) {
int axisLineThickness = 1;
int verticalEndX;
int verticalEndY;
int horizontalEndX;
int horizontalEndY;
Paint axisPaint = new Paint();
axisPaint.setColor(Color.WHITE);
axisPaint.setStrokeWidth(axisLineThickness);
double theta;
for(int i = 90; i < 360; i += 180) {
theta = toRadians(i);
verticalEndX = centerX + (int) ((cos(theta)) * radius);
verticalEndY = centerY + (int) ((sin(theta)) * radius);
verticalAxis.moveTo(centerX, centerY);
verticalAxis.lineTo(verticalEndX, verticalEndY);
}
canvas.drawPath(verticalAxis, axisColor);
for(int i = 90; i < 360; i += 180) {
theta = toRadians(i);
horizontalEndX = centerX + (int) ((cos(theta)) * radius);
horizontalEndY = centerY + (int) ((sin(theta)) * radius);
horizontalAxis.moveTo(centerX, centerY);
horizontalAxis.lineTo(verticalEndX, verticalEndY);
}
canvas.drawPath(horizontalAxis, axisColor);
}
I know I can make the axis draw if I add the following to the vertical and horizontal for loops respectively:
Vertical For Loop:
canvas.drawLine(centerX, centerY, verticalEndX, verticalEndY, paint);
Horizontal For Loop:
canvas.drawLine(centerX, centerY, horizontalEndX, horizontalEndY, paint);
But I don't want to solve the issue this way, I want to correct what is wrong with my paths. Can anyone tell me why the points aren't adding to my path correctly? The loop should only go through twice which creates a line for each side of the axis. Ie. One loop creates the top of the vertical axis and the second loop creates the bottom part.
How do I get my paths create that full line and then draw it outside of the loop?
Paint's default style appears to be FILL, so maybe just having a line in your path is confusing things. Try setting it to STROKE:
axisPaint.setStyle(Paint.Style.STROKE);
See Paint.Style
Related
I need to make lucky wheel like view, and there texts are drawn regarding the radius, as you can see image below. ( there you can see red line, I want to draw texts along that red line )
This is the result I want to achieve but, right now with my method, it just draws text based on circle like below
private void drawText(Canvas canvas, float tempAngle, float sweepAngle, String text) {
Path path = new Path();
Log.d("mytag", "tempAngle = " + tempAngle + ", sweepAngle = " + sweepAngle);
path.addArc(range, tempAngle, sweepAngle);
float textWidth = textPaint.measureText(text);
int hOffset = (int) (radius * Math.PI / mWheelItems.size() / 2 - textWidth / 2);
int vOffset = (radius / 2 / 3) - 15; // here 15 is distance from image
canvas.drawTextOnPath(text, path, hOffset, vOffset, textPaint);
}
Instead of creating an arc to draw the text on, you need a path from the outside of the circle to the center. I think you need something like this
int radius = 180;
float centerX = width/2f;
float centerY = height/2f
double radians = radius * Math.PI / 180;
float x = (float)Math.sin(radians);
float y = (float)-Math.cos(radians);
Path path = new Path();
path.moveTo(x,y);
path.lineTo(centerX, centerY);
canvas.drawTextOnPath(text, path, hOffset, vOffset, textPaint);
First, find the slice centre points.
Kotlin sample snippet
val arcCenter = startAngle + (arcProgress / 2)
//middle point radius is half of the radius of the circle
val pointRadius = size.width / 4
/*Calculate the x & y coordinates
* find points using angle and radius
*https://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates
* */
val x =
(pointRadius * cos(Math.toRadians(arcCenter.toDouble()))) +
size.center.x
val y =
(pointRadius * sin(Math.toRadians(arcCenter.toDouble()))) +
size.center.y
Then Rotate your canvas to the arch centre angle, Draw your text and restore the canvas to a normal position
it.nativeCanvas.rotate( arcCenter, x, y)
it.nativeCanvas.drawText(...)
it.nativeCanvas.rotate( -arcCenter, x, y)
I am trying to create a spray can tool in Android for a Graffiti app. I want to achieve something similar done in the below image
Dripping Spray Can Sample image
Requirements: If somebody is spraying the can then it should drip some color downwards while drawing a spray line
I am currently using the following code, but not getting the correct results:
if (bufferPaint == null) {
bufferPaint = new Paint();
bufferPaint.setAntiAlias(true);
bufferPaint.setDither(true);
bufferPaint.setXfermode(null);
if (mPaint == null)
setupColor(0f, 100f);
}
int alpha = Math.round((float) 100 / 100 * 255);
bufferPaint.setAlpha(alpha);
private void paintOneDab(float x, float y) {
float radius = 5 / 2f;
float scatter = 500 / 100f;
x += radius 2 scatter (1 - 2 (float) Math.random());
y += radius 2 scatter (1 - 2 (float) Math.random());
float hardness = 20 / 100f;
positions[0] = 0;
positions[1] = (float) (Math.sqrt(hardness));
positions[2] = 1;
bufferPaint.setShader(new RadialGradient(x, y, radius, colors, positions, Shader.TileMode.CLAMP));
mCanvas.save();
int angle = 180;
mCanvas.rotate(angle, x, y);
int roundness = 100;
mCanvas.scale(1f, 100f / roundness, x, y);
mCanvas.drawCircle(x, y, radius, bufferPaint);
mCanvas.restore();
}
I am trying to modify a little this library: https://github.com/Shinelw/ColorArcProgressBar
And this is what i've done so far, without the purple circle indicator:
arc progress bar
My question is: how can i animate the purple circle along with the progress(as shown in the image)?
Inside ColorArcProgressBar class that extends View, at onDraw method, this is how the progress is draw: canvas.drawArc(bgRect, startAngle, currentAngle, false, progressPaint);
and the animation is
private void setAnimation(float last, float current, int length) {
progressAnimator = ValueAnimator.ofFloat(last, current);
progressAnimator.setDuration(length);
progressAnimator.setTarget(currentAngle);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
currentAngle = (float) animation.getAnimatedValue();
curValues = currentAngle / k;
}
});
progressAnimator.start();
}
I managed to position the purple bitmat at the start of the progress like this:
canvas.drawBitmap(mIcon,bgRect.left+mIcon.getWidth()/2 +30, bgRect.bottom - 40 +mIcon.getHeight()/2 , null);
Now, how can I animate it along the arc like the progress?
Didn't try this out, if it's not right it's close...
// since currentAngle is a "sweep" angle, the
// final angle should be current + start
float thetaD = startAngle + currentAngle;
if (thetaD > 360F) {
thetaD -= 360F;
}
// convert degrees to radians
float theta = (float) Math.toRadians(thetaD);
// polar to Cartesian coordinates
float x = (float) (Math.cos(theta) * bgRect.width() / 2) + bgRect.centerX();
float y = (float) (Math.sin(theta) * bgRect.height() / 2) + bgRect.centerY();
canvas.drawBitmap(mIcon, x - mIcon.getWidth()/2, y - mIcon.getHeight()/2 , null);
It helped that your bitmap is circular, so we didn't have to rotate that...
I am trying to create a pad-like view in android. I got a circle that follows user's gestures and I am using distance to keep the circle of going outside the main circle of the pad control.
My problem is I want the circle to keep following the gesture, but to stay inside of the main circle. I am using the formula for finding a point using angle and radius, but it does some funky stuff.
I am translating the canvas, so that the center of the main circle is at 0, 0.
Here is the code:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(this.mainRadius, this.mainRadius);
canvas.drawCircle(0, 0, this.mainRadius, this.debugPaint);
canvas.drawCircle(this.handleX, this.handleY, this.handleRadius, this.handlePaint);
}
private void translateHandle(MotionEvent event) {
int x = (int) (event.getX() - this.mainRadius);
int y = (int) (event.getY() - this.mainRadius);
double distance = distanceFromCenter(x, y);
if (distance <= this.maxDistance) {
this.handleX = x;
this.handleY = y;
} else {
float angle = (float) Math.toDegrees(Math.atan2(y, x));
if (angle < 0)
angle += 360;
this.handleX = (int) ((this.mainRadius - this.handleRadius) * Math.cos(angle));
this.handleY = (int) ((this.mainRadius - this.handleRadius) * Math.sin(angle));
}
//onTranslateHandle(distance);
}
And here is the funky stuff in a gif image:
I cannot verify this change into your code snippet but do hope it gives some idea how to proceed further anyway;
private void translateHandle(MotionEvent event) {
float x = event.getX() - this.mainRadius;
float y = event.getY() - this.mainRadius;
double distance = distanceFromCenter(x, y);
if (distance > this.maxDistance) {
// If distance is i.e 2.0 and maxDistance is 1.0 ==> adjust is 0.5
// which repositions x and y making distance 1.0 maintaining direction
double adjust = this.maxDistance / distance;
x = (float)(x * adjust);
y = (float)(y * adjust);
}
this.handleX = (int)x;
this.handleY = (int)y;
}
I can update the answer where needed if this does not give any useful results.
This question is in continuation to my previous doubt
Now I am trying to make a guage view. I am drawing a scale but the alignment is not proper and I am not able to figure out the problem. Here is my code:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
w= canvas.getWidth();
h=canvas.getHeight();
DrawRange(canvas,innerRadius,outerRadius);
}
here innerRadius =250;
and outer radius = 300;
private void DrawRange(Canvas canvas,int r,int R) {
RectF rect = new RectF(canvas.getWidth()/2- r, canvas.getHeight()/2-r, canvas.getWidth()/2+r, canvas.getHeight()/2+r);
RectF rect1 = new RectF(canvas.getWidth()/2- R, canvas.getHeight()/2-R, canvas.getWidth()/2+R, canvas.getHeight()/2+R);
Paint scalePaint = new Paint();
scalePaint.setStyle(Paint.Style.STROKE);
scalePaint.setColor(0x9f004d0f);
scalePaint.setStrokeWidth(2);
scalePaint.setAntiAlias(true);
scalePaint.setTextSize(35.0f);
scalePaint.setTypeface(Typeface.SANS_SERIF);
scalePaint.setTextScaleX(0.4f);
scalePaint.setTextAlign(Paint.Align.CENTER);
canvas.drawOval(rect1, scalePaint);
canvas.drawOval(rect, scalePaint);
canvas.save(Canvas.CLIP_SAVE_FLAG);
int xc = 0;
for (int i = 0; i < totalNicks; i++) {
float y1 = 330;
float y2 = y1 + 5;
if (i % 5 == 0) {
canvas.drawText(""+xc, r-15, y2 , scalePaint);
xc+=5;
}else{
canvas.drawLine(r, y1, r, y2, scalePaint);
}
canvas.rotate(degreesPerNick, w/2, h/2);
}
canvas.restore();
}
I wonder if you are drawing the text and the dashes in the wrong place. The key reference point is the centre of the circles:
int cX = canvas.getWidth()/2;
int cY = canvas.getHeight()/2;
The other key reference is the difference between the two radii:
int deltaR = R - r;
The dashes and text are always drawn at 12 o'clock, say 20% above the inner circle to 1/3 of the way from the outer circle:
int dashInnerY = cY - r - deltaR/5; // 20% of the way between inner and outer radii
int dashOuterY = cY - R + deltaR/3; // 1/3 of the way between outer and inner radii
Then to render a dash:
canvas.drawLine(cX, dashInnerY, cX, dashOuterY, scalePaint);
And the number:
canvas.drawText(""+xc, cX, dashInnerY, scalePaint);