I have read the android spill on this method tons of times and it isn't ringing any bells. Bellow is a part of my code:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
boolean CollisionTest;
Rect jSquare = new Rect();
Rect mSquare = new Rect();
jSquare.set(0,500,600,400);
mSquare.set(0, 500,700, 100);
canvas.drawRect(mSquare, Some Color..);
canvas.drawRect(jSquare, Some Color...);
CollisionTest = Rect.intersects(jSquare, mSquare);
if (ColisionTest==true){
canvas.drawColor(Color.RED);
}
From the documentation for set
public void set (int left, int top, int right, int bottom)
Set the rectangle's coordinates to the specified values. Note: no range checking is performed, so it is up to the caller to ensure that left <= right and top <= bottom.
500 > 100
Related
I'm trying to draw a parabola with delay, using custom view. So far I've learned that I need to use #Override onDraw method, but 1. I can't make my parabola discrete and 2. I don't know how to program it so the shape is created step-by-step (with delay).
I also need to draw it after click of a button, so that is another complication for me. Right now I'm trying to draw a simple line step-by-step but this snippet don't work:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(path, paint);
int x1 = 10;
int x2 = 100;
int y1 = 10;
int y2 = 100;
int diff = x2-x1;
for (int i = 0; i<diff; i++){
canvas.drawLine(x1, y1, x1+1, y1+1, paint);
x1++;
y1++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I can give you some tricks but please finish it your self.
You have to use a timer to refresh your component, if use this, it will refresh "onDraw" each 100ms.
private Handler handler = new Handler();
private Runnable AlarmRunnable = new Runnable() {
#Override
public void run() {
handler.postDelayed(this, 100);
invalidate();
}
};
define global variables instead of local.
int cc = 0;
int x1 = 10;
int x2 = 100;
int y1 = 10;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (cc++ > 100) // STOP HANDLER AFTER COUNTER GETS DONE
handler.removeCallbacks(AlarmRunnable);
System.out.println("CC:" + cc);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStrokeWidth(lineWidth);
paint.setColor(Color.WHITE);
for (int i = 0; i<cc; i++){
canvas.drawLine(x1, y1, x1 + 1, y1 + 1, paint);
x1++;
y1++;
}
}
start handeler in Constructor
public YOURCOMPONENT(Context context, AttributeSet attrs) {
super(context, attrs);
handler.post(AlarmRunnable);
....
}
Rendering a Discrete Parabola
As for drawing a discrete parabola, you should draw points (or circles with a radius size of your choice, but centered at the points) along the different x and y coordinates with a larger step size.
For example, you can draw a parabola from x=-1 to x=1 with a step size of 1 by drawing at the following (x, y) points: (-1, 0), (0, 4), (1, 0).
You should make sure that the way you scale your x-axis on your graph, is in a way that there is greater than 1 pixel distance between the points to make it look discrete.
Animated onDraw
Regardless of whether your drawing logic within onDraw is correct or not, you are running a long operation with Thread.sleep() on a UI callback, which is bad practice.
Since you are drawing the whole parabola within one call of onDraw, I would assume the whole image is rendered at once rather than animated.
Looking at a similar question, you should create another thread that is in charge of a rendering loop for your custom view, to create an animation where you draw each frame.
I'm trying to add a custom Drawable which extends Drawable to my actionBar. This needs to be a custom drawable, since I want to draw on top of a supplied icon (but that's not the issue).
I've added the icon to the menu in my activity like so:
BadgedIconDrawable drawable = new BadgedIconDrawable(getContext())
.setIcon(icon);
mMenu.add(0, menuItemId, 0, "")
.setIcon(drawable)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
In the BadgedIconDrawable I take a bitmap for the Icon which I then draw on the canvas:
#Override
public void draw(#NonNull Canvas canvas) {
canvas.drawBitmap(mIcon.getBitmap(), null, new Rect(0, 0, mWidth, mHeight), mIconPaint);
}
Where the width and height are 24dp, which seems to be the right size for the icon.
The problem is that unlike a regular drawable that's passed to the setIcon for the mMenu, it doesn't seem to align correctly. I can't find how to get it aligned to the center. Image below illustrates the issue. The middle Icon is set through the BadgedIconDrawable.
EDIT
While the below snippet worked, I soon figured this would only work for the toolbar. Not anymore when used in a regular ImageView. So the trick is to use a Rect as to where the bitmap should be drawn. This would have the regular bounds, but when it should be translated, tell the custom Drawable to do so, by modifying the Rect like so:
// On the fragment/activity create the Drawable, translate it and add to the menu.
public void addBadgedActionBarButton(Drawable icon, int color, String badgeLabel, int menuItemId) {
if (mMenu == null) {
throw new IllegalStateException("mMenu = null, Are you sure you are calling addActionBarButton from initMenu()?");
} else {
BadgedIconDrawable drawable = new BadgedIconDrawable(getContext());
drawable.translate(-drawable.getWidth() / 2, -drawable.getHeight() / 2, drawable.getWidth() / 2, drawable.getHeight() / 2)
.setIcon(icon);
mMenu.add(Menu.NONE, menuItemId, Menu.NONE, "")
.setIcon(drawable)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
}
// In the BadgedIconDrawable have a function that sets the mDstRect to the translated Rect.
public BadgedIconDrawable translate(int left, int top, int right, int bottom) {
mDstRect = new Rect(left, top, right, bottom);
return this;
}
// In the BadgedIconDrawable draw function use the mDstRect to draw on the correct position.
#Override
public void draw(#NonNull Canvas canvas) {
canvas.drawBitmap(mIcon.getBitmap(), null, mDstRect, mIconPaint);
}
With some wild guessing I managed to try to add a negative top and left, which seems to place it in the correct spot. This seems to do the trick.
#Override
public void draw(#NonNull Canvas canvas) {
int halfWidth = mWidth / 2;
int halfHeight = mHeight / 2;
canvas.drawBitmap(mIcon.getBitmap(), null, new Rect(-halfWidth, -halfHeight, halfWidth, halfHeight), mIconPaint);
}
As is, 100 pink circles (same bitmap) appear scattered randomly over the phone screen (as is supposed to). When I tap one of the circles, that circle should disappear (change to the background color). I think I have a fundamental misunderstanding of Android and View in general.I think I have a couple obvious errors (that are not so obvious to me, but I've been staring at it so long that I figured I needed some help). Currently, the screen shows the random circles but nothing more. Touching the screen does nothing. Any better ideas to make the circles disappear? It recently reorganized all the bitmaps when you touched it, but I did something recently, and it stopped. The bitmap is 30px by 30px.
public class DrawV extends View {
private Bitmap bit_dot;
private int width;
private int height;
public int[] width_array = new int[100];
public int[] height_array = new int[100];
private View dotV = (View)findViewById(R.id.bigdocpic);//bitmap
Random rand = new Random();
public DrawV(Context context) {
super(context);
bit_dot = BitmapFactory.decodeResource(getResources(), R.drawable.dot_catch);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
width = metrics.widthPixels;
height = metrics.heightPixels;
}
#Override
//draws 100 randomly placed similar bitmaps
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int height_dimension;
int width_dimension;
for (int i = 0; i < 100; i++){
height_dimension = rand.nextInt(height) + 1;
width_dimension = rand.nextInt(width) + 1;
canvas.drawBitmap(bit_dot, width_dimension, height_dimension, null);
width_array[i] = width_dimension;//
height_array[i] = height_dimension;//
}
}
#Override
public boolean onTouchEvent(MotionEvent event){
Paint p = new Paint();
p.setColor(Color.WHITE);
Path path = new Path();
Canvas c = new Canvas();
for (int i = 0; i < 100; i++){
if ((event.getX() == width_array[i]) && (event.getY() == height_array[i]))
c.drawCircle(width_array[i], height_array[i], 15, p);
}
invalidate();
return false;//false or true?
}
//set visibility of bitmap to invisible
public boolean onTouch(View v, MotionEvent event) {
dotV.setVisibility(View.INVISIBLE);
invalidate();
return false;//false or true? not understanding
}}
Help?
Your onTouchEvent isn't really doing anything important as-is, and you don't have the concept of a circle object.
onDraw should really be drawing these circles from an array/list created earlier - say a List<MyCircles> or MyCircles[]. On touch, you could iterate through all of your circles until you find one that is closest, remove that circle from the array or list, then invalidate.
The reason nothing is happening at all is even though you're drawing those circles again in onTouchEvent, you're redrawing everything yet again in onDraw (invalidate() calls draw/onDraw).
Ideally, create your list of circles in your initializer, draw them in onDraw, and update them in onTouch (That is, delete). There may be a simpler way to do this but this is, at the very least, a more proper approach.
I have an xml layout that has 3 input boxes and a 'generate' button.
When the user puts in there values there I'd like to draw a triangle underneath it
I know how to create a new view and go to it, but I'm not sure how to draw it on the same view being that I'm working with an xml view.
Below is a screenshot of what I want to do.
Thank you
http://i.stack.imgur.com/9oBJV.png
You could create a custom view class.
class Triangle extends View {
private int vertexA, vertexB, vertexC;
public Triangle(Context ctx){
this(ctx,null);
}
public Triangle(Context ctx, AttributeSet attrs){
this(ctx,attrs,0);
}
public Triangle(Context ctx, AttributeSet attrs, int defStyle){
super(ctx,attrs,defStyle);
}
public void setSides(int a, int b, int c){
this.vertexA = a;
this.vertexB = b;
this.vertexC = c;
this.invalidate();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Try for a width based on our minimum
int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
int w = resolveSizeAndState(minw, widthMeasureSpec, 1);
// Whatever the width ends up being, ask for a height that would let the triangle
// get as big as it can
int minh = MeasureSpec.getSize(w) - (int)mTextWidth + getPaddingBottom() + getPaddingTop();
int h = resolveSizeAndState(MeasureSpec.getSize(w) - (int)mTextWidth, heightMeasureSpec, 0);
setMeasuredDimension(w, h);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
Path path = new Path();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.TRANSPARENT);
c.drawPaint(paint);
// start the path at the "origin"
path.MoveTo(10,10); // origin
// add a line for side A
path.lineTo(10,this.vertexA);
// add a line for side B
path.lineTo(this.vertexB,10);
// close the path to draw the hypotenuse
path.close();
paint.setStrokeWidth(3);
paint.setPathEffect(null);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
c.drawPath(path, paint);
}
}
Note that I've hard coded the origin (the bottom left corner - the right angle) and only drawn 2 sides, since the hypotenuse is drawn by the closed path (this saves doing any extra maths). You'll want to play with onMeasure and scale your triangle as you need. Something like this:
path.lineTo(10, this.vertexA * yScale);
path.lineTo(this.vertexB * xScale ,10);
You're activity should check that the 3 values do indeed represent the sides of a right angled triangle, then call setSides(). I've added all 3 sides, although we are only using a and b. You could remove c if you prefer.
Please note that this is not copy/paste code. You will need to adapt it but it should give you a head start. Good luck.
Just put your custom view into the layout below the button. The exact xml to use depends on the type of your top level view container (which is probably a RelativeLayout).
To make it invisible at first you can set its visibility to INVISIBLE. When it should appear set the visibility to VISIBLE.
I have five shape draw able rectangular, I have to set the rectangle at angle of (-20,-15,-10,-5,0)Degree. Each Rectangular have four colors shade. Now I need to animate each rectangle one by one and if user drag left to right then top rectangle moves to left to right.
Problem is, I can’t move each rectangle separately. How I can identify and implement each rectangle separately?
Here sample snapshot that i have to do.
http://postimage.org/image/13sa96sbo/
public ColorFanDraw(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvasObject) {
int x = 100;
int y = 50;
int width = 70;
int convasSize =200;
Paint thePaint = new Paint();
thePaint.setColor(mTouchedColor-200);
canvasObject.rotate(-15, centerX,centerY);
canvasObject.drawRect(new Rect(x,y,x+width,y+convasSize), thePaint);
thePaint.setColor(mTouchedColor-50);
canvasObject.rotate(10, centerX,centerY);
canvasObject.drawRect(new Rect(x,y,x+width,y+convasSize), thePaint);
canvasObject.rotate(10, centerX,centerY);
thePaint.setColor(mTouchedColor);
canvasObject.drawRect(new Rect(x,y,x+width,y+convasSize), thePaint);
rotation = AnimationUtils.loadAnimation(contextObj,
R.anim.view_transition_in_left);
ImageView img = new ImageView(contextObj);
img.startAnimation(rotation);
}
You would need to store the rectangle objects in a variable before you draw them onto the Canvas.
Rect rectangle1 = new Rect(x,y,x+width,y+convasSize);
canvasObject.drawRect(rectangel1, thePaint);
Rect rectangle2 = new Rect(x,y,x+width,y+convasSize);
canvasObject.drawRect(rectangel2, thePaint);
and so on.
Then you can refer to the individual rectangles wherever you are doing your animation.