Based on the code I've used for my canvas drawing and the screenshot regarding that, I'm trying to fill a specific red rectangle but it's not working. What can be done to ensure that ONLY the rectangle on the top row, 2nd from left is filled?
public class Car extends View {
public Car(Context context) {
super(context);
init();
}
public Car(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Car(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
Paint paint;
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(4);
// paint.setStyle(Paint.Style.STROKE); // delete line for filled rect
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = canvas.getWidth();
int h = canvas.getHeight();
int rectWidth = w / 5;
int space = w / 15;
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
for (int i = 0; i < 4; i++) {
int left = i * (rectWidth + space);
int right = left + rectWidth;
if (i == 2){
paint.setStyle(Paint.Style.STROKE); // delete line for filled rect
}
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
}
}
This way only the specified rectangle will be filled (only top 2nd one).
paint.setStyle(Paint.Style.STROKE); //add this
for (int i = 0; i < 4; i++) {
int left = i * (rectWidth + space);
int right = left + rectWidth;
if (i == 1){
paint.setStyle(Paint.Style.FILL); // change to this
}
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
paint.setStyle(Paint.Style.STROKE);//add this
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
If you want only the 2nd bottom to be filled:
paint.setStyle(Paint.Style.STROKE); //you can remove this now
for (int i = 0; i < 4; i++) {
paint.setStyle(Paint.Style.STROKE);//add this
int left = i * (rectWidth + space);
int right = left + rectWidth;
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
if (i == 1){
paint.setStyle(Paint.Style.FILL); // change to this
}
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
And if you want both the 2nd top and bottom filled:
paint.setStyle(Paint.Style.STROKE); //you can remove this now
for (int i = 0; i < 4; i++) {
paint.setStyle(Paint.Style.STROKE);//add this
int left = i * (rectWidth + space);
int right = left + rectWidth;
if (i == 1){
paint.setStyle(Paint.Style.FILL); // change to this
}
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
Related
I'm trying to plot a graph on a View using a canvas. So far so good it plots correctly as show in the next image:
Desired Output
once you tap on the screen the expected result should clear the screen and plot a new graph but instead draws on top of it resulting in this:
Actual Output
private List<Float> xPosList, yPosList;
private List<Path> pathList;
private Path path;
private Paint paint;
private final Paint clearPaint = new Paint();
public Plotter(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
this.xPosList = new ArrayList<>();
this.yPosList = new ArrayList<>();
this.pathList = new ArrayList<>();
this.paint = new Paint();
this.paint.setStrokeWidth(20);
this.paint.setColor(Color.GREEN);
this.clearPaint.setColor(Color.BLACK);
generateData();
}
private void generateData() {
int min = 5;
int max = 100;
double random = 0;
float xPos = 0;
float yPos = 0;
for (int i = 1; i <= 20; i++) {
random = min + Math.random() * (max - min);
xPos = 50 * i; //50 pixels
yPos = (float)random;
this.xPosList.add(xPos);
this.yPosList.add(yPos);
path = new Path(); //Create path
path.moveTo(xPos, yPos); //Add values to path
this.pathList.add(path); //Add path to pathList
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
generateData();
break;
case MotionEvent.ACTION_UP:
//invalidate();
break;
}
//invalidate(); //Refresh canvas
return true; //Activate event
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
p.setColor(Color.GREEN);
p.setStrokeWidth(10);
p.setStyle(Paint.Style.FILL);
/***
* Better use 50 by 50 pixels
*/
float startX = 0;
float startY = canvas.getHeight(); //Start at the bottom (max height)
float nextX = 0;
float nextY = 0;
for (int i = 0; i < this.xPosList.size(); i++){
nextX = this.xPosList.get(i);
nextY = canvas.getHeight() - (this.yPosList.get(i) * 10); //Add 50 offset
canvas.drawLine(startX, startY, nextX, nextY, p);
startX = nextX;
startY = nextY;
}
}
}
How do I properly clear screen?
I have tried
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
seen from other questions but it does not work.
Actually it does not have anything to do with your clear color - the screen gets cleared correctly. The problem is the xPosList and likewise the yPosList ArrayList.
As soon as the user taps the screen the generateData() function gets called which keeps adding elements to both ArrayList. But: you never clear those! So as soon as you tap the screen twice, the ArrayList's contain random data from the first and the second tap.
You need to clear those right before the for-loop:
this.xPosList.clear();
this.yPosList.clear();
for (int i = 1; i <= 20; i++) {
random = min + Math.random() * (max - min);
xPos = 50 * i; //50 pixels
yPos = (float)random;
this.xPosList.add(xPos);
this.yPosList.add(yPos);
path = new Path(); //Create path
path.moveTo(xPos, yPos); //Add values to path
this.pathList.add(path); //Add path to pathList
}
So I want to draw two lines that cross in the middle (like an x), and I want to draw this onto my randomly generated bitmap. Does anyone know how I can make the line diagonl?
public static Bitmap randomImage(int width, int height) {
Bitmap ranImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Random rand = new Random(System.currentTimeMillis());
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++) {
int r = rand.nextInt(255);
int g = rand.nextInt(255);
int b = rand.nextInt(255);
int color = Color.rgb(r, g, b);
ranImage.setPixel(x, y, color);
}
//initialise a new canvas instance
Canvas canvas = new Canvas(ranImage);
//intialise a new paint instance to draw the line
Paint paint = new Paint();
//line color
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
//line width in pixels
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
//set a pizel value to offset the line from the canvas edge
int offset = 50;
//draw a line on canvas at the center postion ....for now
canvas.drawLine(
offset,
canvas.getHeight()/2,
canvas.getWidth()-offset,
canvas.getHeight()/2,
paint
);
return ranImage;
}
I want to create a irregular quadrilateral using 4 draggable points in android as given in image below.
desired quadrilateral I want
so that user can manually drag the points one by one and put create quadrilateral as they want using 4 points what I've tried yet is given below.
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* DrawView class holds corner objects and handle them by drawing
* overlay.
*
* #author Chintan Rathod (http://chintanrathod.com)
*/
public class DrawView2 extends View {
Point point1, point3;
Point point2, point4;
/**
* point1 and point 3 are of same group and same as point 2 and point4
*/
int groupId = -1;
private ArrayList < ColorBall > colorballs = new ArrayList < ColorBall > ();
// array that holds the balls
private int balID = 0;
// variable to know what ball is being dragged
Paint paint;
Canvas canvas;
public DrawView2(Context context) {
super(context);
paint = new Paint();
setFocusable(true); // necessary for getting the touch events
canvas = new Canvas();
// setting the start point for the balls
point1 = new Point();
point1.x = 50;
point1.y = 20;
point2 = new Point();
point2.x = 150;
point2.y = 20;
point3 = new Point();
point3.x = 150;
point3.y = 120;
point4 = new Point();
point4.x = 50;
point4.y = 120;
// declare each ball with the ColorBall class
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point1));
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point2));
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point3));
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point4));
}
public DrawView2(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public DrawView2(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
setFocusable(true); // necessary for getting the touch events
canvas = new Canvas();
// setting the start point for the balls
point1 = new Point();
point1.x = 50;
point1.y = 20;
point2 = new Point();
point2.x = 150;
point2.y = 20;
point3 = new Point();
point3.x = 150;
point3.y = 120;
point4 = new Point();
point4.x = 50;
point4.y = 120;
// declare each ball with the ColorBall class
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point1));
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point2));
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point3));
colorballs.add(new ColorBall(context, R.drawable.ic_cancel, point4));
}
// the method that draws the balls
#Override
protected void onDraw(Canvas canvas) {
// canvas.drawColor(0xFFCCCCCC); //if you want another background color
// paint.setAntiAlias(true);
// paint.setDither(true);
paint.setColor(Color.parseColor("#55000000"));
paint.setStyle(Paint.Style.FILL);
paint.setStrokeJoin(Paint.Join.ROUND);
// mPaint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(5);
canvas.drawPaint(paint);
paint.setColor(Color.parseColor("#55FFFFFF"));
if (groupId == 1) {
canvas.drawLine(point1.x + colorballs.get(0).getWidthOfBall() ,
point3.y + colorballs.get(2).getWidthOfBall() , point3.x + colorballs.get(2).getWidthOfBall() ,
point1.y + colorballs.get(0).getWidthOfBall() , paint);
} else if(groupId == 2){
canvas.drawLine(point2.x + colorballs.get(1).getWidthOfBall() ,
point1.y + colorballs.get(0).getWidthOfBall() , point1.x + colorballs.get(0).getWidthOfBall(),
point2.y + colorballs.get(1).getWidthOfBall() , paint);
} else if(groupId ==3){
canvas.drawLine(point2.x + colorballs.get(1).getWidthOfBall() ,
point4.y + colorballs.get(3).getWidthOfBall() , point4.x + colorballs.get(3).getWidthOfBall(),
point2.y + colorballs.get(1).getWidthOfBall() , paint);
} else {
canvas.drawLine(point3.x + colorballs.get(2).getWidthOfBall() ,
point4.y + colorballs.get(3).getWidthOfBall() , point4.x + colorballs.get(3).getWidthOfBall(),
point3.y + colorballs.get(2).getWidthOfBall() , paint);
}
BitmapDrawable mBitmap;
mBitmap = new BitmapDrawable();
// draw the balls on the canvas
for (ColorBall ball: colorballs) {
canvas.drawBitmap(ball.getBitmap(), ball.getX(), ball.getY(),
new Paint());
}
}
// events when touching the screen
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
int X = (int) event.getX();
int Y = (int) event.getY();
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
// touch down so check if the finger is on
// a ball
balID = -1;
groupId = -1;
for (ColorBall ball: colorballs) {
// check if inside the bounds of the ball (circle)
// get the center for the ball
int centerX = ball.getX() + ball.getWidthOfBall();
int centerY = ball.getY() + ball.getHeightOfBall();
paint.setColor(Color.CYAN);
// calculate the radius from the touch to the center of the ball
double radCircle = Math.sqrt((double)(((centerX - X) * (centerX - X)) + (centerY - Y) * (centerY - Y)));
if (radCircle < ball.getWidthOfBall()) {
balID = ball.getID();
if (balID == 1 ) {
groupId = 1;
canvas.drawLine(point1.x, point3.y, point3.x, point1.y,
paint);
} else if(balID == 2){
groupId = 2;
canvas.drawLine(point1.x, point2.y, point2.x, point1.y,
paint);
} else if(balID == 3){
groupId = 3;
canvas.drawLine(point4.x, point2.y, point4.x, point2.y,
paint);
} else {
groupId = 4;
canvas.drawLine(point4.x, point3.y, point3.x, point4.y,
paint);
}
invalidate();
break;
}
invalidate();
}
break;
case MotionEvent.ACTION_MOVE:
// touch drag with the ball
// move the balls the same as the finger
if (balID > -1) {
colorballs.get(balID).setX(X);
colorballs.get(balID).setY(Y);
paint.setColor(Color.CYAN);
if (groupId == 1) {
colorballs.get(0).setX(colorballs.get(0).getX());
colorballs.get(0).setY(colorballs.get(0).getY());
colorballs.get(2).setX(colorballs.get(2).getX());
colorballs.get(2).setY(colorballs.get(2).getY());
canvas.drawLine(point3.x, point1.y, point3.x, point1.y,
paint);
} else if(groupId == 2){
colorballs.get(1).setX(colorballs.get(1).getX());
colorballs.get(1).setY(colorballs.get(1).getY());
colorballs.get(3).setX(colorballs.get(3).getX());
colorballs.get(3).setY(colorballs.get(3).getY());
canvas.drawLine(point4.x, point2.y, point4.x, point2.y,
paint);
}
invalidate();
}
break;
case MotionEvent.ACTION_UP:
// touch drop - just do things here after dropping
break;
}
// redraw the canvas
invalidate();
return true;
}
}
the problem I am facing is that when I am trying to drag a one point it also drags another point with it but can anyone please let me help with this. My code output is given below which is not a desired thing I want.
the shape I am getting
Well I am able to solve this issue
canvas.drawLine(point2.x + colorballs.get(1).getWidthOfBall() / 2,
point2.y + colorballs.get(1).getWidthOfBall() / 2,
point1.x + colorballs.get(0).getWidthOfBall() / 2, point1.y + colorballs.get(0).getWidthOfBall() / 2, paint);
canvas.drawLine(point4.x + colorballs.get(3).getWidthOfBall() / 2,
point4.y + colorballs.get(3).getWidthOfBall() / 2,
point1.x + colorballs.get(0).getWidthOfBall() / 2, point1.y + colorballs.get(0).getWidthOfBall() / 2, paint);
canvas.drawLine(point3.x + colorballs.get(2).getWidthOfBall() / 2,
point3.y + colorballs.get(2).getWidthOfBall() / 2,
point2.x + colorballs.get(1).getWidthOfBall() / 2, point2.y + colorballs.get(1).getWidthOfBall() / 2, paint);
canvas.drawLine(point3.x + colorballs.get(2).getWidthOfBall() / 2,
point3.y + colorballs.get(2).getWidthOfBall() / 2,
point4.x + colorballs.get(3).getWidthOfBall() / 2, point4.y + colorballs.get(3).getWidthOfBall() / 2, paint);
I want to animate multiple paths in sequence, for example, I have
Path[] line and Path[] circle
so when I do for example
line[0].moveTo(x, y);
graphPath[j].lineTo(x, y);
I want to animate this part first and when
finish I want to add circle in same x,y postion
circle[0].addCircle(x, y, 10, Path.Direction.CW);
what I have done so far inside onDraw()
#Override
protected void onDraw(Canvas canvas) {
for (int j = 0; j < 2; j++) {
if (dataPoints2[j] != null) {
float x = leftPadding;
float y = height * getDataPoint(0, j) + topPadding;
graphPath[j].moveTo(x, y);
circlePath[j].addCircle(x, y, 10, Path.Direction.CW);
for (int i = 1; i < dataPoints2[j].size(); i++) {
x = width * (((float) i ) / dataPoints2[j].size()) + leftPadding;
y = height * getDataPoint(i, j) + topPadding;
graphPath[j].lineTo(x, y);
circlePath[j].addCircle(x, y, 10, Path.Direction.CW);
}
}
}
PathMeasure measure = new PathMeasure(graphPath[0], false);
length = measure.getLength();
ObjectAnimator animator = ObjectAnimator.ofFloat(Chart.this, "phase", 1.0f, 0.0f);
animator.setDuration(8000);
animator.start();
for (int j = 0; j < graphPath.length; j++) {
canvas.drawPath(graphPath[j], linePaint[j]);
canvas.drawPath(circlePath[j], circlePaint[j]);
}
}
public void setPhase(float phase){
linePaint[0].setPathEffect(createPathEffect(length, phase, 0.0f));
invalidate();
}
private static PathEffect createPathEffect(float pathLength, float phase, float offset)
{
return new DashPathEffect(new float[] { pathLength, pathLength },
Math.max(phase * pathLength, offset));
}
this will draw the circle then animate the line connecting the circle points
what I need is to animate the line and draw circle when the line reaches every x,y points
I'm trying to learn how collision detection works in android and I am doing so using Android rectangles.
I need to be able to detect a collision of the second rectangles top, left and bottom walls but the issue is that the first rectangle is able to go straight in to the second rectangle through the top left corner.
Below is a snippet of the code that I am using:
Snippet from GameView2 class:
private Shape s1 = new Shape(this, Color.BLACK, 0, 100, 50, 50);
private Shape s2 = new Shape(this, Color.BLUE, 200, 100, 50, 50);
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
this.drawBackground(canvas);
s1.onDraw(canvas);
s2.onDraw(canvas);
s1.x+=s1.vx;
s1.y+=s1.vy;
//left wall collision
if(s1.x+s1.width==s2.x && s1.y+s1.height > s2.y && s1.y < s2.y + s2.height){
s1.vx = 0;
}
//top wall
else if(s1.y+s1.height==s2.y && s1.x+s1.width > s2.x && s1.x < s2.x+s2.width){
s1.vy = 0;
}
else{
s1.vx = 2;
}
}
Shape class:
public class Shape{
protected GameView2 game_view;
protected int x;
protected int y;
protected int vx;
protected int vy;
protected int width;
protected int height;
protected int color;
public Shape(GameView2 game_view, int color, int x, int y, int width, int height) {
this.game_view = game_view;
this.x = x;
this.y = y;
this.vx = 2;
this.vy = 0;
this.width = width;
this.height = height;
this.color = color;
}
public Rect getRect(){
return new Rect(x, y, x + width, y + height);
}
public void onDraw(Canvas canvas){
Paint paint = new Paint();
Rect rec = new Rect(x, y, x + width, y + height);
paint.setColor(color);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(rec, paint);
}
}
Here is a really simple algorithm for collision between two rectangles.
x1+width1 < x2 || x2+width2 < x1 || y1+height1 < y2 || y2+height2
If the statement above is true, no collision occurs. Else, the two rectangles are colliding.