Search code examples
androidtouch-event

Android - Accessing member variable from onTouchEvent()


First I precise that I saw a lot of questions for similar issues, but no one for my exact case, so I have to ask my own question.

I'm trying to create an application that collect strokes when the user touches a view. I created a class named WritingView that extends View. In this class, I overrided the onTouchEvent() method to draw the strokes and collect the coordinates in an ArrayList named currentStroke. It works, until I try to access the content of the array that contains the coords in the MainActivity, when I click a button, where it is always empty.

Here is the code of the WritingView class, I give it all in case but I think the problem comes from onTouchEvent, the rest is here to draw the collecting canvas and the strokes on the screen, which works :

public class WritingView extends View{
private Canvas drawCanvas;
private Bitmap bitmapCanvas;
private Path inkPath;
private Paint ink, inkCanvas;
private Context context;
private ArrayList<Float> currentStroke;

public WritingView(Context c) {
    super(c);
    init(c);
}

public WritingView(Context c, AttributeSet attrs) {
    super(c, attrs);
    init(c);
}

public WritingView(Context c, AttributeSet attrs, int defStyleAttr) {
    super(c, attrs, defStyleAttr);
    init(c);
}

public void init(Context c) {
    this.inkPath = new Path();
    this.ink = new Paint();
    this.context = c;
    this.currentStroke = new ArrayList<Float>();

    // Get the screen size
    WindowManager wm = (WindowManager) this.context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);

    // Set ink parameters
    ink.setColor(0xFF660000);
    ink.setAntiAlias(true);
    ink.setStrokeWidth(15);
    ink.setStyle(Paint.Style.STROKE);
    ink.setStrokeJoin(Paint.Join.ROUND);
    ink.setStrokeCap(Paint.Cap.ROUND);

    this.inkCanvas = new Paint(Paint.DITHER_FLAG);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    this.bitmapCanvas = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    this.drawCanvas = new Canvas(bitmapCanvas);
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(bitmapCanvas, 0, 0, inkCanvas);
    canvas.drawPath(inkPath, ink);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    float touchX = event.getX();
    float touchY = event.getY();

    switch(event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
            inkPath.moveTo(touchX, touchY);
            Log.d(TAG, "onTouchEvent: ACTION_DOWN_EVENT - X=" + touchX + ", Y=" + touchY );
            break;
        case MotionEvent.ACTION_MOVE:
            inkPath.lineTo(touchX, touchY);
            this.currentStroke.add(touchX);
            this.currentStroke.add(touchY);
            Log.d(TAG, "onTouchEvent: ACTION_MOVE_EVENT - X=" + touchX + ", Y=" + touchY );
            break;
        case MotionEvent.ACTION_UP:
            drawCanvas.drawPath(inkPath, ink);
            Log.d(TAG, "onTouchEvent: ACTION_UP_EVENT - X=" + touchX + ", Y=" + touchY );
            inkPath.reset();
            break;
        default:
            return false;
    }

    invalidate();
    return true;
}

public ArrayList<Float> getCurrentStroke() {
    Log.d(TAG, "getCurrentStroke: size : " + this.currentStroke.size());
    return this.currentStroke;
}
}

And the code of the MainActivity :

public class MainActivity extends AppCompatActivity {
static final int RECO_REQUEST = 0;
private WritingView writingView;
private Intent intent;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    writingView = new WritingView(this);
    setContentView(R.layout.activity_main);

    final Button button = (Button) findViewById(R.id.recognizeButton);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            startReco();
        }
    });
}

public void startReco() {
    ArrayList<Float> coords = writingView.getCurrentStroke();

    Log.d(TAG, "onClick: size : " + coords.size());
    for(int i = 0; i < coords.size(); i++) {
        Log.d(TAG, "onClick: " + i + " : " + coords.get(i));
    }
}
}

As I said, the array seems to be empty when I try to access it from the MainActivity, but I know (I tested it) that the coordinates are put into it in the onTouchEvent method.

Thanks for your help.

In addition, here is the xml file, to show the display of the activity, and how WritingView is added on it :

<TextView
    android:id="@+id/textResult"
    android:layout_width="578dp"
    android:layout_height="146dp"
    android:layout_marginEnd="8dp"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="16dp"
    android:text="Results :"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<Button
    android:id="@+id/recognizeButton"
    android:text="Start recognition"
    android:layout_width="300dp"
    android:layout_height="80dp"
    app:layout_constraintTop_toBottomOf="@+id/textResult"
    app:layout_constraintBottom_toTopOf="@+id/writingView" />

<com.myscript.testapplication.WritingView
    android:id="@+id/writingView"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_marginBottom="8dp"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:layout_marginTop="8dp"
    android:layout_weight="1"
    android:background="#E3EAE7"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@id/recognizeButton"/>

Solution

  • Seems you have 2 WritingViews. First you have one in your layout file, and you also create a new one in the Activity.

    Try this:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        writingView = (WritingView)findViewById(R.id.writingView);
        ....
    }
    

    Alternatively, you can remove the WritingView from the layout file, and use addView() to add it to the main activity instead.