canvas.drawCircle sometimes working, sometimes not - android

I bought the book Programming Android, and it's a little confusing and disappointing on how they have different code in their Github (https://github.com/bmeike/ProgrammingAndroid2Examples/tree/master/AndroidUIDemo) and their book. I'm stuck in an example that teaches how to draw a circle in a random point, with the color that is assigned to the button, like, when I click the RED button, it should draw a red circle in a view.
I did some extra code and somehow I managed to get it working. Here is my onDraw method:
#Override
protected void onDraw(Canvas canvas)
{
paint.setStyle(Style.STROKE);
paint.setColor(hasFocus() ? Color.BLUE : Color.GRAY);
canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, paint);
if (this.points == null) return;
paint.setStyle(Style.FILL);
for (Point p : points.getAllPoints())
{
paint.setColor(p.getColor());
canvas.drawCircle(p.getX(), p.getY(),
p.getDiameter(), paint);
}
}
Sometimes it works, sometimes not, BUT when it works, it draws a thin, large oval shape.
p.getDiameter() is ALWAYS 6. Even if I put it to a fixed 6, the effect is the same.
Also, there is some strange thing happening: If I replace p.getY() and p.getX() by 50, it will never draw anything on the screen. 50 should not be out of the screen bounds.
In the image below you can see what it's being rendered and some code I use to create the views.
Here is some extra relevant code.
Setting the pointView size (the place where I draw points):
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
pointView.setLayoutParams(new android.widget.LinearLayout.LayoutParams(root.getWidth(), root.getHeight()/2));
}
Add an OnCLickListener to the button, so when I click it, it should draw a circle.
button1.setOnClickListener(new OnClickListener() //I'll not put the Red button here, for the sake of brevity.
{
#Override
public void onClick(View arg0)
{
makeDot(pointModel, pointView, Color.GREEN);
}
});
And the makeDot method:
private final Random rnd = new Random();
void makeDot(Points points, PointView pointView, int color)
{
points.addPoint(
rnd.nextFloat()*pointView.getWidth(),
rnd.nextFloat()*pointView.getHeight(),
color, POINT_DIAMETER /*always 6*/);
}
(I think POINT_DIAMETER should be POINT_RADIUS but it's OK for now.)
So, how can I get it to draw a round circle in a random position in the screen?

Here are a few ideas:
In addPoint, try generating the coordinates like this:
points.addPoint(
rnd.nextInt() % pointView.getWidth(),
rnd.nextInt() % pointView.getHeight(),
color, POINT_DIAMETER /*always 6*/);
In your onClick method, try adding a call to invalidate:
button1.setOnClickListener(new OnClickListener() //I'll not put the Red button here, for the sake of brevity.
{
#Override
public void onClick(View arg0)
{
makeDot(pointModel, pointView, Color.GREEN);
pointView.invalidate();
}
});
When you set the Style.FILL, set the color as well:
paint.setStyle(Style.FILL);
paint.setColor(hasFocus() ? Color.BLUE : Color.GRAY);
Also, remove this line of code:
pointView.setScaleX(20);
That's all I could think of for now.
Hope this helps :)

Related

Change View size to match content

I have a class Token which extends View. I override the onDraw method to draw two rects. After that i want to change the size of the Token object to match the size of the rects. For testing i added an onClickListener which should print out "Test"
layout = (RelativeLayout) findViewById(R.id.layout);
Paint p = new Paint();
Token a = new Token(0,0, Token.ONE, p, this);
layout.addView(a);
a.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("test");
}
});
The Token class:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
tSize = canvas.getWidth()/Activity.SIZE;
paint.setColor(Color.BLACK);
r.set(0, 0, tSize, tSize);
canvas.drawRect(r, paint);
r.set(tSize, 0, 2 * tSize, tSize);
canvas.drawRect(r, paint);
}
So far so good. The problem is that it is always printing out "Test", no matter where i press on the screen. I figured that is because the View, which holds this two rects is the the size of the whole screen.
So i tried LayoutParams:
setLayoutParams(new RelativeLayout.LayoutParams(tSize*2, tSize);
This results in the rects not showing up at all(i think they got to small). I tried some other numbers:
setLayoutParams(new RelativeLayout.LayoutParams(600, 600);
This is working. The rects show up and the Listener only works in a 600x600 field. The only Problem is the rects are smaller than i want them to be. My guess is that their size is relative to the size of the view they are in.
How would i achive that my View is exactly (tSize*2, tSize) with the rects filling it out?
you may override onMeasure method to change the GameTokenView's size.

Android moving a shape faster on Canvas

I have a class which is extended from ImageView (lets call it 'surface'). On onDraw method, a little dot is drawing on canvas. When I click a button I try to move this dot to another location. You can consider like manual version of translate animation. It works but now I try to figured out speed of this moving. I mean I want dot moving faster.
Relevant part of surface :
private float actual_x=100,actual_y=100; // Dot is drawn on 100,100 at beginning
private float increase_x,increase_y;
private boolean isMovingResume=false;
private int moving_counter;
public void changeLocation(float x,float y){
isMovingResume=true;
moving_counter=0;
increase_x=(x-actual_x)/50;
increase_y=(y-actual_y)/50;
invalidate(); // This trigger onDraw method
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(actual_x,actual_y,15,fill_paint);
if(isMovingResume){
actual_x=actual_x+increase_x;
actual_y=actual_y+increase_y;
if(moving_counter==49){ // Moving will end after 50 redraw
isMovingResume=false;
}
else{
moving_counter++;
}
invalidate(); //redraw
}
}
And my button click :
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
surface.changeLocation(200,200);
}
});
Like I said, it works but I want it more faster. For example, in this case moving time is 2 second, How can I make it 0,5 second ?
Thanks for all replies.
You need to switch to surfaceview or even faster textureview, both use a canvas as well, and have better performance. Textureview especially as it is hardware accelerated and I also feel it behaves better than surfaceview. That or even consider going to GLSurfaceView.
You can see some example code of surfaceview and textureview: Here

Animating ActionBar's icon

I have an ActionBar icon (the main one on the left, not an action item) that I would like to animate.
I am setting my ActionBar's icon in my Activity like this:
getSupportActionBar().setIcon(icon)
where icon is a Drawable produced by a library that converts a custom XML view into a bitmap. This XML view is a RelativeLayout with a background image and a TextView on top.
Today, when I have to update the TextView I simply re-generate the icon and call setIcon again. Instead, I would like to get a hold of my TextView and apply some animation effect on it, like fade-out and then fade-in after updating it (maybe never having to call setIcon, just re-use the same one).
Not sure how to go about this. Can someone recommend an approach?
EDIT: trying this approach:
In MyActivity:
Drawable myDrawable = new MyDrawable();
supportActionBar.setIcon(myDrawable);
and:
public class MyDrawable extends Drawable {
private Paint paint;
private RectF rect;
public MyDrawable() {
this.paint = new Paint();
this.rect = new RectF();
}
#Override
public void draw(Canvas canvas) {
paint.setARGB(255, 0, 255, 0);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
rect.right = 20f;
rect.bottom = 20f;
canvas.drawRoundRect(rect, 0.5f, 0.5f, paint);
}
#Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}
Nothing shows up. I verified that onDraw gets called. Something suspicious to me is that canvas has both height & width set to 1.
A proper approach for it would be to forget the XML layout and create a custom Drawable.
An instance of this custom drawable will be set to the icon on the ActionBar and call invalidateSelf() whenever necessary to redraw (due to animation, for example).
The drawable can hold reference to other drawables (e.g. BitmapDrawable to have something from the /res/ folder or a Color or Gradient drawable for a background shade) and call (for example) bgDraw.draw(canvas) during the onDraw callback.
It can also draw stuff directly on the canvas that is given to it during onDraw callback. With the canvas you can draw circle, lines, areas, path and text directly on it.
edit:
very simple animation example (didn't check the code, likely typos):
private long animationTime;
public void doAnimation(){
animationTime = System.currentTimeMilis() + 3000; // 3 seconds
invalidateSelf();
}
public void onDraw(Canvas canvas){
// do your drawing.
// You can use difference between
// currentTimeMilis and animationTime for status/position
...
// at the end
if(animationTime > System.currentTimeMilis())
invalidateSelf();
}

How to draw a simple line over buttons

I am making a noughts and crosses game and i want to draw a line over the winning combination. The playing grid consists of a grid of buttons and i want the line to be over the top of them. At the moment the line will draw but it will have a black background hiding the grid of buttons even though it is set to transparent.
How would i make the transparency work then clear when i want to start a new game?
I hope that makes sense.
This is the draw class:
public class DrawView extends View {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public DrawView(Context context) {
super(context);
paint.setColor(Color.RED);
paint.setStrokeWidth(10);
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawLine(0, 0, 1000, 1000, paint);
}
}
This is the part of the method in the game:
public void checkWin() {
if (squares[1] == 1 & squares[2] == 1 & squares[3] == 1) {
for (int i = 1; i <= 9; i++) {
buttons[i].setEnabled(false);
}
drawView = new DrawView(this);
drawView.setBackgroundColor(Color.TRANSPARENT);
setContentView(drawView);
Intent d = new Intent(this, Win.class);
startActivity(d);
If you want to draw a line with alpha, use :
paint.setAlpha(125);
paint.setColor(Color.RED);
paint.setStrokeWidth(10);
Just remember to set it back after you use it, if you use paint else where.
Note:
0 = completely transparent
255 = completely opaque
Edit: Okay, I think you might be trying to clear the canvas, so it starts off blank.
Draw clear onto it, with PorterDuff to clear it.
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
canvas.drawLine(0, 0, 1000, 1000, paint);
}
I dont think your setBackgroundColor works because you have overriden the draw method. But I could be wrong, the above code should fix the issue.

controll bitmap image manually

I,m taking my first step into movement of bitmaps. From bits on the internet i,ve created this simple code. The bitmap moves across the screen from top left to top right it goes off the screen and back on at 0,0. What i want to do is add a button or method to manually move the image. I,m only using this single class and have noticed it does not use the main_activity xml Or does it?? If someone could show me on this 1 direction i can duplicate for the other directions. If youd like to add code so doesnt go off screen would be a bonus
public class MainActivity extends Activity {
int x=0;
int y=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new myView(this)); }
private class myView extends View{
public myView(Context context) {
super(context); }
#Override
protected void onDraw(Canvas canvas) {
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.richinch);
if (x < canvas.getWidth()){x +=10;}
else {x=0;}
canvas.drawBitmap(myBitmap, x, y, null);
invalidate();
}}}
Ive added this to the code and read a little on OnTouch listener. How would i add that to the region or Rectangle this would be very helpfull so effectively i,m using the Bitmap as a button if was button id know with onclick, Basicall im trying to make 2 Bitmap buttons to move the image Left Right for now.Eventually all directions. Please use names im using unless creating summit eg int etc
Paint green = new Paint();
green.setColor(Color.RED);
green.setStyle(Paint.Style.FILL);
////creating the shape////
Rect rect= new Rect();
rect.set(0, 0,x+50, x+50);
canvas.drawRect(rect,green);
Region region = new Region(0, 950, 100, 1030);
I am not exactly sure what you want to achieve, but if you would like to make an animation, avoid using onDraw() and just let ObjectAnimator do the "moving" for you. Here's a detailed tutorial on it.
The minimum code you need:
ObjectAnimator animation = ObjectAnimator.ofFloat(yourObject, "x", xDest);
animation.setDuration(500); // milliseconds
animation.start();
You are not using any xml
this part here:
setContentView(new myView(this)); is where you would add your xml file setContentView(R.layout.mainxml)
If you want to move around a bitmap with the touch of your finger check out these tutorials. They do exactly this and you will learn to use a SurfaceView
http://www.eis4u.com/2012/02/13/playing-with-graphics-in-android-part-i/
http://www.eis4u.com/2012/02/13/playing-with-graphics-in-android-part-ii/
http://www.eis4u.com/2012/02/13/playing-with-graphics-in-android-part-iii/

Categories

Resources