Zhanna Sarsenbayeva
Zhanna Sarsenbayeva

Reputation: 15

Draw a circle in Android Canvas when previous circle was selected at predefined positions

This is my first time using Canvas in Android. I am creating an app that would display circles at certain positions on the screen one at a time (positions are selected randomly). New circle should be drawn after the previous one was selected/touched, and the previous one should disappear. I have some ideas about it: to keep an arraylist of Point objects(each object contains x,y coordinate of the centre of the circle) and randomly select one each time the circle is drawn on the screen. So first I am populating an array of points. I also know how to randomly select the element from arraylist. My biggest confustion is how to connect onDraw and onTouchEvent methods with each other? I know I should check if the circle was selected and only then draw a new circle at the randomly selected position, but I m not sure how to make a call for onDraw() method from the onTouchEvent...

Could you please help with this issue? My code is below:

package com.example.researcher.heatmap;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

/**
 * TODO: document your custom view class.
 */
public class MyView extends View {

    Paint paint;
    ArrayList<Point> points = new ArrayList<>();



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

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        // Load attributes
        paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);
        populateArrayList();

    }


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


        paint.setStyle(Paint.Style.STROKE);
            canvas.drawColor(Color.WHITE);
            int i=1; // should be random, will randomize later

            for(Point p: points) {
                p.x = points.get(i).x;
                p.y = points.get(i).y;

                canvas.drawCircle(p.x, p.y, 50, paint);
            }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:


                int i=1;

                for(Point p: points) {
                    Canvas canvas = new Canvas();
                    p.x = points.get(i).x;
                    p.y = points.get(i).y;
                    canvas.drawCircle(p.x, p.y, 50, paint);
                }

                postInvalidate();

            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                break;
            }
        }
        postInvalidate();
        return true;

    }

    public void populateArrayList(){
        points.clear();
        points.add(new Point(120, 120));
        points.add(new Point(150, 320));
        points.add(new Point(280, 200));
    }

}

Upvotes: 0

Views: 1846

Answers (2)

Zhanna Sarsenbayeva
Zhanna Sarsenbayeva

Reputation: 15

Thank you Chris for your help! I really appreciate it.

Here is my solution if someone will need it for reference

package com.example.researcher.heatmap;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * TODO: document your custom view class.
 */
public class MyView extends View {

    Paint paint;
    ArrayList<Point> points = new ArrayList<>();
    private int pointsPos = 0; //Which point we will be drawing
    public float x;
    public float y;
    public int radius = 150;



    public MyView(Context context) {
        super(context);
        x = this.getX();
        y = this.getY();
        init();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        x = this.getX();
        y = this.getY();
        init();
    }

    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        x = this.getX();
        y = this.getY();
        init();
    }

    private void init() {
        // Load attributes
        paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);
        populateArrayList();

    }


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


        paint.setStyle(Paint.Style.STROKE);
        canvas.drawColor(Color.WHITE);

        canvas.drawCircle(points.get(pointsPos).x, points.get(pointsPos).y, radius, paint);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:

            case MotionEvent.ACTION_UP:
                //Check if the point press is within the circle
                if(contains(event, points.get(pointsPos))){

                    Random r = new Random(System.nanoTime());
                    pointsPos = r.nextInt(points.size());; //between 0 and points.length

                    postInvalidate();
                }


            case MotionEvent.ACTION_CANCEL: {
                break;
            }
        }
        postInvalidate();
        return true;

    }

    private boolean contains(MotionEvent event, Point point) {
        float xTouch = event.getX();
        float yTouch = event.getY();
        if ((xTouch - point.x) * (xTouch - point.x) + (yTouch - point.y) * (yTouch - point.y) <= radius * radius) {
            return true;
        }
        else {
            return false;
        }
    }

    public void populateArrayList(){
        points.clear();
        points.add(new Point(220, 1020));
        points.add(new Point(550, 320));
        points.add(new Point(780, 500));
    }

}

Upvotes: 1

Chris Handy
Chris Handy

Reputation: 366

Class var

private int state = 0     //0 normal, 1 new circle
private int pointPos = 0; //Which point we will be drawing

onDraw was overwriting the x/y of all your other points

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


    paint.setStyle(Paint.Style.STROKE);
    canvas.drawColor(Color.WHITE);

    if(state == 1){
        pointPos = random(); //between 0 and points.length
        state = 0;
    }

    canvas.drawCircle(points.get(pointsPos).x, points.get(pointsPos).y, 50, paint);

}

onTouchEvent: Drawing should only be done on the ondraw, use flags/states to keep track of what you should be doing on the next draw call

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:

            //Though these days this is usually done on the up event
            //Check if the point press is within the circle
            if(contains(event, points.get(pointPos))){
                state = 1;
                postInvalidate();
            }



        case MotionEvent.ACTION_MOVE:
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL: {
            break;
        }
    }
    postInvalidate();
    return true;

}

Upvotes: 0

Related Questions