Nikola Lukic Nikola Lukic - 1 month ago 22
Android Question

Android canvas - setWillNotDraw(false) not working

Here is the code :
It is activity class with custom view class . This code is only working example for canvas for me .

I just need recall in loop onDraw function (like animationframe in javascript canvas2d ).
I can always use timers to make a call but maybe there is some low level nice way for that. I am pionir in android dev.

Question is updated ! - I use class name instead instance name . No need for static for sure.
Current status : crash on activate activity.

public class CanvasNativeSurface extends AppCompatActivity {

private GoogleApiClient client;


private myview myView;

private Handler mHandler;

class myview extends View
{

private void init() {


}

public myview(Context context) {
super(context);
init();

}



int x=80;
int y=180;

@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);

x=80;

y = y + 1;

int radius=40;
Paint paint=new Paint();
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawCircle(x,y, radius, paint);





}


public void move()
{
y= y+30;// 30 is value for testing
// change it to whatever you want.
invalidate();

}

}



@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

ViewGroup view1;
view1 = (ViewGroup) findViewById( R.id.activity_canvas_native_surface );
/// setContentView(R.layout.activity_canvas_native_surface );
setContentView(new myview(this));


mHandler = new Handler();
mHandler.postDelayed(mRunnable, 1000);

}


private Runnable mRunnable = new Runnable() {

@Override
public void run() {

myView.move();
mHandler.postDelayed(this, 1000);
}
};


y = y + 1 ; Must push object to the bottom . Circle has no movement .

Catch in log :
Attempt to invoke virtual method 'void....CanvasNativeSurface$myview.move()' on a null object reference

Also in adroid studio on mouse hover say : myView never assingned

Answer

MyView.jav // separate file

public class MyView extends View
{

    private   int x=80,y=180,radius=40;
    private Paint paint;

    public MyView(Context context) {
        super(context);
        init();
    }

    public void init() {

        paint=new Paint();
        paint.setColor(Color.parseColor("#CD5C5C"));
    }


    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        canvas.drawCircle(x,y, radius, paint);

    }

    public void move()
    {
      y= y+30;// 30 is value for testing
      // change it to whatever you want.
      invalidate();

    }
}

And in your activity you can do something like

private MyView myView;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myView = new MyView(this);
    setContentView(myView);

    mHandler = new Handler();
    mHandler.postDelayed(mRunnable, 1000);

}

private Runnable mRunnable = new Runnable() {

    @Override
    public void run() {

        myView.move();
        mHandler.postDelayed(this, 1000);
    }
};

Finally don't forget to

mHandler.removeCallbacksAndMessages(mRunnable);

When you want to stop.

As i said earlier you don't need setWillNotDraw(false); and your constructor is called only once.

You probably need a timer mechanism to move the circle every second or something. I hope you got the idea and you can make changes accordingly.

If you are looking for animation

public class MyView extends View
{

    private int x=80,y=180,radius=40;
    private Paint paint;

    public MyView(Context context) {
        super(context);
        init();
    }

    public void init() {

        paint=new Paint();
        paint.setColor(Color.parseColor("#CD5C5C"));
    }


    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        canvas.drawCircle(x,y, radius, paint);

    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

     public void setStateOnObject(){

        // 900 is the end value
        ObjectAnimator animateBottom = ObjectAnimator.ofFloat(this,"y",y,900);
        animateBottom.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                postInvalidate();
            }
        });
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animateBottom);
        animatorSet.setDuration(5000).start();
    }
}

And instead of handler you would do

  myView.setStateOnObject();