El botón de Android ha llamado setOnTouchListener pero no anula performClick

113

Cuando trato de agregar onTouchListner()a un botón, me da la

Button ha llamado a setOnTouchListener pero no anula performClick

advertencia. ¿Alguien sabe cómo arreglarlo?

1

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

Error:

La vista personalizada ha llamado setOnTouchListener pero no anula performClick Si una vista que anula onTouchEvent o usa un OnTouchListener no implementa también performClick y lo llama cuando se detectan clics, es posible que la vista no maneje las acciones de accesibilidad correctamente. La lógica que maneja las acciones de clic debe ubicarse idealmente en Ver # performClick, ya que algunos servicios de accesibilidad invocan performClick cuando debe ocurrir una acción de clic.

kas
fuente
La vista personalizada ImageViewha llamado a setOnTouchListener pero no anula performClick Si una vista que anula onTouchEvent o usa un OnTouchListener no implementa también performClick y lo llama cuando se detectan clics, es posible que la vista no maneje las acciones de accesibilidad correctamente. La lógica que maneja las acciones de clic debe ubicarse idealmente en Ver # performClick ya que algunos servicios de accesibilidad invocan performClick cuando debe ocurrir una acción de clic.
kas
Vea mi respuesta aquí: stackoverflow.com/questions/47170075/…
lambda

Respuestas:

134

Esta advertencia surge porque Android quiere recordarle que piense en las personas ciegas o con discapacidad visual que pueden estar usando su aplicación. Le sugiero que vea este video para obtener una descripción general rápida de cómo es eso.

Las vistas estándar de la interfaz de usuario (como Button, TextViewetc.) están configuradas para proporcionar a los usuarios ciegos la retroalimentación adecuada a través de los servicios de accesibilidad. Cuando intenta manejar los eventos táctiles usted mismo, corre el peligro de olvidarse de proporcionar esa retroalimentación. Para eso es la advertencia.

Opción 1: crear una vista personalizada

El manejo de eventos táctiles suele ser algo que se realiza en una vista personalizada. No descarte esta opción demasiado rápido. No es tan difícil. A continuación, se muestra un ejemplo completo de TextViewque se anula para manejar eventos táctiles:

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();
    }
}

Entonces lo usarías así:

<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"/>

Consulte mi otra respuesta para obtener más detalles sobre cómo crear una vista personalizada.

Opción 2: silenciar la advertencia

Otras veces puede ser mejor simplemente silenciar la advertencia. Por ejemplo, no estoy seguro de qué es lo que desea hacer con un Buttonevento táctil para el que necesita. Si se va a hacer un botón personalizado y llamado performClick()en onTouchEventcomo lo hice anteriormente para el encargo TextView, entonces sería conseguir llamó dos veces cada vez porque Buttonya se llama performClick().

Aquí hay un par de razones por las que podría querer silenciar la advertencia:

  • El trabajo que está realizando con su evento táctil es solo visual. No afecta el funcionamiento real de su aplicación.
  • Tienes un corazón frío y no te importa hacer del mundo un lugar mejor para las personas ciegas.
  • Eres demasiado vago para copiar y pegar el código que te di en la Opción 1 anterior.

Agregue la siguiente línea al principio del método para suprimir la advertencia:

@SuppressLint("ClickableViewAccessibility")

Por ejemplo:

@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;
        }
    });
}
Suragch
fuente
1
Estaba usando vistas personalizadas debido a que usaba diferentes fuentes. Como ahora en Api 26 introduce una nueva característica, las fuentes en xml y para versiones anteriores usan la biblioteca de soporte 26 que admite hasta Api 16. Así que eliminé todas las vistas personalizadas. Y aparece esta estúpida advertencia y la solución es volver a crear algunas de esas vistas personalizadas para las que estoy usando setOnTouchListener. jajaja: D Tan extraño
Shan Xeeshi
19
Me pregunto si Google se da cuenta de cuántas horas de desarrollador desperdician con esto. Quiero decir, ¿tal vez podrían manejar esto dentro de la API? pasar tiempo subclasificando vistas o incluso buscando cómo resolver su advertencia es una pérdida de muchas horas.
TatiOverflow
¿Qué pasa si necesitas el MotionEvent eventobjeto en tu doSomething()método? Necesito comprobar event.getY().
Mateus Gondim
@MateusGondim, tengo que decir que todavía no soy muy competente en la implementación performClick(). Mi pensamiento inicial es que si event.getY()no es parte integral del evento de clic real (es decir, efectos visuales de la interfaz de usuario), entonces mueva esa lógica de regreso a onTouchEvent(). De lo contrario, podría crear una variable miembro de clase para almacenar el Yvalor de la última acción . También te sugiero que consultes el código fuente para ver algunas de las vistas estándar para ver cómo lo implementa Android. Necesito estudiarlos más yo mismo.
Suragch
1
@sisisisi, la advertencia aparece cuando anula onTouchEvent()pero no performClick(). Eso podría incluir un deslizamiento o un clic o cualquier otro evento táctil que esté tratando de capturar.
Suragch
17

Solución:

  1. Cree una clase que amplíe Button o cualquier vista que esté usando y anule performClick ()

    class TouchableButton extends Button {
    
        @Override
        public boolean performClick() {
            // do what you want
            return true;
        }
    }
  2. ¡Ahora use este TouchableButton en xml y / o código y la advertencia desaparecerá!

Sjd
fuente
18
Esto es realmente asqueroso. ¿No hay forma de utilizar las vistas existentes?
Leche
@Milk Nope. android.widget.Buttonestá codificado por lo que no le permite hacer esto. Y parece ser muy intencional por parte del equipo de desarrollo de Android.
tom_mai78101
11

¿Ha intentado agregar:

view.performClick()

o agregando la anotación suppresslint:

@SuppressLint("ClickableViewAccessibility")

?

lambda
fuente
2
Si. Esta advertencia con la edición android studio 3.0
kas
1
De acuerdo, tengo una alternativa para solucionar esa advertencia. consulte: stackoverflow.com/questions/47170075/…
lambda
1

Los controles de vista personalizados pueden requerir un comportamiento de evento táctil no estándar. Por ejemplo, un control personalizado puede usar el método de escucha onTouchEvent (MotionEvent) para detectar los eventos ACTION_DOWN y ACTION_UP y activar un evento de clic especial. Para mantener la compatibilidad con los servicios de accesibilidad, el código que maneja este evento de clic personalizado debe hacer lo siguiente:

Genere un AccessibilityEvent apropiado para la acción de clic interpretada. Habilite los servicios de accesibilidad para realizar la acción de clic personalizada para los usuarios que no pueden usar una pantalla táctil. Para manejar estos requisitos de manera eficiente, su código debe anular el método performClick (), que debe llamar a la súper implementación de este método y luego ejecutar las acciones requeridas por el evento click. Cuando se detecta la acción de clic personalizado, ese código debe llamar a su método performClick ().

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

vlazzle
fuente