184

When I try to add onTouchListner() to a button, it gets me the

Button has setOnTouchListener called on it but does not override performClick

warning. Does anyone know how to fix it?

1

btnleftclick.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        return false;
    }
});

Error:

Custom view has setOnTouchListener called on it but does not override performClick If a View that overrides onTouchEvent or uses an OnTouchListener does not also implement performClick and call it when clicks are detected, the View may not handle accessibility actions properly. Logic handling the click actions should ideally be placed in View#performClick as some accessibility services invoke performClick when a click action should occur.

0xCursor
  • 2,242
  • 4
  • 15
  • 33
Garry
  • 2,256
  • 2
  • 11
  • 14
  • Custom view `ImageView` has setOnTouchListener called on it but does not override performClick If a View that overrides onTouchEvent or uses an OnTouchListener does not also implement performClick and call it when clicks are detected, the View may not handle accessibility actions properly. Logic handling the click actions should ideally be placed in View#performClick as some accessibility services invoke performClick when a click action should occur. – Garry Nov 05 '17 at 04:50
  • Please see my answer here : https://stackoverflow.com/questions/47170075/kotlin-ontouchlistener-called-but-it-does-not-override-performclick/47170922#47170922 – lambda Nov 08 '17 at 07:38
  • Possible duplicate of [Custom view ... overrides onTouchEvent but not performClick](https://stackoverflow.com/questions/27462468/custom-view-overrides-ontouchevent-but-not-performclick) – Vega Aug 29 '19 at 10:30

6 Answers6

230

This warning comes up because Android wants to remind you to think about the blind or visually impaired people who may be using your app. I suggest you watch this video for a quick overview about what that is like.

The standard UI views (like Button, TextView, etc.) are all set up to provide blind users with appropriate feedback through Accessibility services. When you try to handle touch events yourself, you are in danger of forgetting to provide that feedback. This is what the warning is for.

Option 1: Create a custom view

Handling touch events is normally something that is done in a custom view. Don't dismiss this option too quickly. It's not really that difficult. Here is a full example of a TextView that is overridden to handle touch events:

public class CustomTextView extends AppCompatTextView {

    public CustomTextView(Context context) {
        super(context);
    }

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

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

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return true;

            case MotionEvent.ACTION_UP:
                performClick();
                return true;
        }
        return false;
    }

    // Because we call this from onTouchEvent, this code will be executed for both
    // normal touch events and for when the system calls this using Accessibility
    @Override
    public boolean performClick() {
        super.performClick();
        doSomething();
        return true;
    }

    private void doSomething() {
        Toast.makeText(getContext(), "did something", Toast.LENGTH_SHORT).show();
    }
}

Then you would just use it like this:

<com.example.myapp.CustomTextView
    android:id="@+id/textview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="20dp"
    android:text="Click me to do something"/>

See my other answer for more details about making a custom view.

Option 2: Silencing the warning

Other times it might be better to just silence the warning. For example, I'm not sure what it is you want to do with a Button that you need touch events for. If you were to make a custom button and called performClick() in onTouchEvent like I did above for the custom TextView, then it would get called twice every time because Button already calls performClick().

Here are a couple reasons you might want to just silence the warning:

  • The work you are performing with your touch event is only visual. It doesn't affect the actual working of your app.
  • You are cold-hearted and don't care about making the world a better place for blind people.
  • You are too lazy to copy and paste the code I gave you in Option 1 above.

Add the following line to the beginning of the method to suppress the warning:

@SuppressLint("ClickableViewAccessibility")

For example:

@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button myButton = findViewById(R.id.my_button);
    myButton.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            return false;
        }
    });
}
Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • 1
    I was using customviews because of using different fonts. As now in Api 26 introduces new feature, fonts in xml and for older version use support library 26 which support till Api 16. So I removed all custom views. And this stupid warning comes up and solution is to create again some of those custom views for which I am using setOnTouchListener. hahaha :D So strange – Zeeshan Aug 27 '18 at 22:14
  • 78
    I wonder if google realize how many developer hours they waste by this. I mean, they could maybe handle this within the api? spending time subclassing views or even searching how to resolve his warning wastes lots of hours. – TatiOverflow Oct 02 '18 at 19:57
  • what if you need the `MotionEvent event` object in your `doSomething()` method? I need to check `event.getY()`. – Mateus Gondim Oct 05 '18 at 14:44
  • @MateusGondim, I have to say that I am still not very competent at implementing `performClick()` yet. My initial thought is if the `event.getY()` is not integral to the actual click event (i.e. visual UI effects), then move that logic back to `onTouchEvent()`. Otherwise you could create a class member variable to store the last action up `Y` value. I also suggest you check out the source code for a few of the standard views so see how Android implements it. I need to study them more myself. – Suragch Oct 06 '18 at 07:55
  • If I understand correctly, when this warning comes up during the detection of a swipe, not a click, I can only do something other than suppression about it if I can somehow detect `ACTION_DOWN` through accessibility, right? – sisisisi Oct 20 '18 at 11:46
  • 1
    @sisisisi, the warning comes up when you override `onTouchEvent()` but not `performClick()`. That could include a swipe or click or any other touch event that you are trying to capture. – Suragch Oct 20 '18 at 16:19
  • 5
    Sometimes the application is not intended for blind people. It's sad, but that's life. – Cequiel Mar 31 '20 at 19:06
  • Wonderful answer! – Linus Aug 02 '21 at 13:42
  • Just throwing in my 2 cents. The entire reason for this, is due to the multiple ways that events are handled (or can be). One of the events of onTouch() is the release of the button, which is the same as performing a click. If not handled properly, and you set up and onClick Listener, both events could fire when you only wanted one version to do so. That said, none of the on-screen annotations are helpful in resolving this. A quick fix options needs to be available for these VERY COMMON situations. The only reason I have been working on this, is due to the extremely annoying yellow highlight. – FoxDonut Jun 13 '23 at 19:48
17

Solution:

  1. Create a class that extends Button or whatever view you are using and override performClick()

    class TouchableButton extends Button {
    
        @Override
        public boolean performClick() {
            // do what you want
            return true;
        }
    }
    
  2. Now use this TouchableButton in xml and/or code and the warning will be gone!

Pang
  • 9,564
  • 146
  • 81
  • 122
Sjd
  • 1,261
  • 1
  • 12
  • 11
12

Have you tried adding :

view.performClick()

or adding suppresslint annotation :

@SuppressLint("ClickableViewAccessibility")

?

lambda
  • 990
  • 1
  • 10
  • 29
  • 4
    Yes. This waring comeup with android studio 3.0 edition – Garry Nov 08 '17 at 06:42
  • 1
    Okay, I have an alternative to fix that warning. please see : https://stackoverflow.com/questions/47170075/kotlin-ontouchlistener-called-but-it-does-not-override-performclick – lambda Nov 08 '17 at 06:48
1

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:

Generate an appropriate AccessibilityEvent for the interpreted click action. 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.

https://developer.android.com/guide/topics/ui/accessibility/custom-views#custom-touch-events

vlazzle
  • 811
  • 9
  • 14
0

At the point in the overridden OnTouchListener, where you interprete the MotionEvent as a click, call view.performClick(); (this will call onClick()).

It is to give the user feedback, e.g. in the form of a click sound.

Cactusroot
  • 1,019
  • 3
  • 16
0

you can suppress a warning

@SuppressLint("ClickableViewAccessibility")

or call performClick()

[Example]

yoAlex5
  • 29,217
  • 8
  • 193
  • 205