Wednesday, September 3, 2014

warning: custom view overrides onTouchEvent but not performClick and #onTouchEvent should call #performClick when a click is detected

If you copy the last example of "Custom View, detect touch to toggle color", you will be warned on onTouchEvent() with message of "MyView overrides onTouchEvent but not performClick"!



Then you override performClick(), you will be warned again with "MyView#onTouchEvent should call .../MyView#performClick when a click is detected"!!!


Android document have mention about "Handling custom touch events":

Custom view controls may require non-standard touch event behavior. For example, a custom control may use the onTouchEvent(MotionEvent) listener method to detect the ACTION_DOWN and ACTION_UP events and trigger a special click event. In order to maintain compatibility with accessibility services, the code that handles this custom click event must do the following:
  1. Generate an appropriate AccessibilityEvent for the interpreted click action.
  2. Enable accessibility services to perform the custom click action for users who are not able to use a touch screen.
To handle these requirements in an efficient way, your code should override the performClick() method, which must call the super implementation of this method and then execute whatever actions are required by the click event. When the custom click action is detected, that code should then call your performClick() method. The following code example demonstrates this pattern.



This video show how to modify MyView.java in last post to remove the warnings.


After changed, MyView.java become:
package com.example.androidtouchview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

 boolean touchOn;
 boolean mDownTouch = false;

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

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

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

 private void init() {
  touchOn = false;
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
    MeasureSpec.getSize(heightMeasureSpec));
 }

 @Override
 protected void onDraw(Canvas canvas) {
  if (touchOn) {
   canvas.drawColor(Color.RED);
  } else {
   canvas.drawColor(Color.GRAY);
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  super.onTouchEvent(event);

  /*
  int action = event.getAction();

  if (action == MotionEvent.ACTION_DOWN) {
   touchOn = !touchOn;
   invalidate();
   return true;
  }

  return false;
  */
  // Listening for the down and up touch events
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
             
             touchOn = !touchOn;
       invalidate();
             
                mDownTouch = true;
                return true;

            case MotionEvent.ACTION_UP:
                if (mDownTouch) {
                    mDownTouch = false;
                    performClick(); // Call this method to handle the response, and
                                    // thereby enable accessibility services to
                                    // perform this action for a user who cannot
                                    // click the touchscreen.
                    return true;
                }
        }
        return false; // Return false for other touch events
 }

 @Override
 public boolean performClick() {
  // Calls the super implementation, which generates an AccessibilityEvent
        // and calls the onClick() listener on the view, if any
        super.performClick();

        // Handle the action for the custom click here

        return true;
 }

}

2 comments: