O botão Android foi chamado por setOnTouchListener, mas não substitui performClick


113

Quando tento adicionar onTouchListner()a um botão, consigo o

O botão setOnTouchListener foi chamado, mas não substitui performClick

Aviso. Alguém sabe como consertar isso?

1

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

Erro:

A exibição personalizada tem setOnTouchListener chamado, mas não substitui performClick Se uma exibição que substitui onTouchEvent ou usa um OnTouchListener também não implementa performClick e chama-o quando cliques são detectados, a exibição pode não lidar com as ações de acessibilidade adequadamente. O tratamento lógico das ações de clique deve ser colocado, idealmente, em Exibir # performClick, pois alguns serviços de acessibilidade chamam performClick quando uma ação de clique deve ocorrer.


A exibição personalizada ImageViewtem setOnTouchListener chamado, mas não substitui performClick Se uma exibição que substitui onTouchEvent ou usa um OnTouchListener também não implementa performClick e chama-o quando cliques são detectados, a exibição pode não lidar com as ações de acessibilidade adequadamente. O tratamento lógico das ações de clique deve ser colocado, idealmente, em Exibir # performClick, pois alguns serviços de acessibilidade chamam performClick quando uma ação de clique deve ocorrer.
kas

Por favor, veja minha resposta aqui: stackoverflow.com/questions/47170075/…
lambda

Respostas:


134

Este aviso surge porque o Android deseja lembrá-lo de pensar sobre os cegos ou deficientes visuais que podem estar usando seu aplicativo. Eu sugiro que você assista a este vídeo para uma rápida visão geral sobre como é.

As visualizações padrão da IU (como Button,TextView etc.) são todas configuradas para fornecer aos usuários cegos um feedback apropriado por meio dos serviços de acessibilidade. Quando você tenta lidar com eventos de toque sozinho, corre o risco de esquecer de fornecer esse feedback. É para isso que serve o aviso.

Opção 1: crie uma visualização personalizada

O tratamento de eventos de toque normalmente é feito em uma visualização personalizada. Não descarte essa opção muito rapidamente. Não é realmente tão difícil. Aqui está um exemplo completo de um TextViewque é substituído para lidar com eventos de toque:

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

Então você o usaria assim:

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

Veja minha outra resposta para mais detalhes sobre como fazer uma visualização personalizada.

Opção 2: silenciando o aviso

Outras vezes, pode ser melhor apenas silenciar o aviso. Por exemplo, não tenho certeza do que você deseja fazer com um para Buttono qual precisa de eventos de toque. Se você fosse fazer um botão personalizado e chamado performClick()em onTouchEventcomo eu fiz acima para o costume TextView, então ele iria ficar chamado duas vezes cada vez, porque Buttonjá chamadasperformClick() .

Aqui estão alguns motivos pelos quais você pode querer apenas silenciar o aviso:

  • O trabalho que você está realizando com seu evento de toque é apenas visual. Isso não afeta o funcionamento real do seu aplicativo.
  • Você tem o coração frio e não se importa em tornar o mundo um lugar melhor para os cegos.
  • Você está com preguiça de copiar e colar o código que forneci na Opção 1 acima.

Adicione a seguinte linha ao início do método para suprimir o aviso:

@SuppressLint("ClickableViewAccessibility")

Por exemplo:

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

1
Eu estava usando visualizações personalizadas por causa do uso de fontes diferentes. Como agora no Api 26 introduz um novo recurso, as fontes em xml e para versões mais antigas usam a biblioteca de suporte 26 que suporta até a Api 16. Portanto, removi todas as visualizações personalizadas. E este aviso estúpido surge e a solução é criar novamente algumas dessas visualizações personalizadas para as quais estou usando setOnTouchListener. hahaha: D Tão estranho
Shan Xeeshi

19
Eu me pergunto se o Google percebe quantas horas de desenvolvedor eles perdem com isso. Quer dizer, eles poderiam lidar com isso dentro da API? gastar tempo criando subclasses de visualizações ou até mesmo procurando como resolver seu aviso desperdiça muitas horas.
TatiOverflow

e se você precisar do MotionEvent eventobjeto em seu doSomething()método? Eu preciso verificar event.getY().
Mateus Gondim

@MateusGondim, devo dizer que ainda não sou muito competente na implementação performClick(). Meu pensamento inicial é se o event.getY()não é parte integrante do evento de clique real (ou seja, efeitos visuais de IU), mova essa lógica de volta para onTouchEvent(). Caso contrário, você poderia criar uma variável de membro de classe para armazenar o Yvalor da última ação . Eu também sugiro que você verifique o código-fonte para algumas das visualizações padrão, então veja como o Android o implementa. Eu mesmo preciso estudá-los mais.
Suragch

1
@sisisisi, o aviso aparece quando você ignora, onTouchEvent()mas não performClick(). Isso pode incluir um toque ou clique ou qualquer outro evento de toque que você está tentando capturar.
Suragch

17

Solução:

  1. Crie uma classe que estenda Button ou qualquer modo de exibição que você esteja usando e substitua performClick ()

    class TouchableButton extends Button {
    
        @Override
        public boolean performClick() {
            // do what you want
            return true;
        }
    }
  2. Agora use este TouchableButton em xml e / ou código e o aviso desaparecerá!


18
Isso é realmente nojento. Não há como usar as visualizações existentes?
Leite de

@Milk Nope. android.widget.Buttonestá codificado, por isso não permite que você faça isso. E parece ser muito intencional da equipe de desenvolvimento do Android.
tom_mai78101

11

Você já tentou adicionar:

view.performClick()

ou adicionando a anotação suppresslint:

@SuppressLint("ClickableViewAccessibility")

?


2
Sim. Este comeup Waring com edição android Studio 3.0
kas

1
Ok, tenho uma alternativa para corrigir esse aviso. consulte: stackoverflow.com/questions/47170075/…
lambda

1

Os controles de visualização personalizados podem exigir um comportamento de evento de toque não padrão. Por exemplo, um controle personalizado pode usar o método de escuta onTouchEvent (MotionEvent) para detectar os eventos ACTION_DOWN e ACTION_UP e acionar um evento de clique especial. Para manter a compatibilidade com os serviços de acessibilidade, o código que lida com esse evento de clique personalizado deve fazer o seguinte:

Gere um AccessibilityEvent apropriado para a ação de clique interpretada. Habilite os serviços de acessibilidade para executar a ação de clique personalizada para usuários que não podem usar uma tela de toque. Para lidar com esses requisitos de maneira eficiente, seu código deve substituir o método performClick (), que deve chamar a superimplementação desse método e, em seguida, executar todas as ações exigidas pelo evento click. Quando a ação de clique personalizado é detectada, esse código deve então chamar o método performClick ().

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.