Estou tendo um problema com meu botão permanecendo em um estado destacado, depois de fazer o seguinte:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
v.performClick();
Log.d("Test", "Performing click");
return true;
}
}
return false;
}
});
}
}
Com relação ao código acima, ao usá-lo, espero que o clique do botão seja manipulado pelo toque e, retornando "true", o tratamento deve parar no touchListener.
Mas esse não é o caso. O botão permanece em um estado destacado, mesmo que o clique esteja sendo chamado.
O que eu recebo é:
Test - calling onClick
Test - Performing click
por outro lado, se eu estiver usando o código a seguir, o botão é clicado, as mesmas impressões, mas o botão não fica preso no estado destacado:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
// v.performClick();
Log.d("Test", "Performing click");
return false;
}
}
return false;
}
});
}
}
Estou um pouco confuso quanto ao que é a cadeia de resposta ao evento de toque. Meu palpite é que é:
1) TouchListener
2) ClickListener
3) ParentViews
Alguém pode confirmar isso também?
android
onclicklistener
android-button
ontouchlistener
Urso polar
fonte
fonte
Respostas:
Essas personalizações não precisam de modificações de programação. Você pode fazer isso simplesmente em
xml
arquivos. Antes de tudo, exclua completamente osetOnTouchListener
método que você forneceonCreate
. Em seguida, defina uma cor do seletor nores/color
diretório da seguinte maneira. (se o diretório não existir, crie-o)res / color / button_tint_color.xml
Agora, defina-o no
app:backgroundTint
atributo do botão :Resultado Visual:
EDITADO: (para resolver o problema do evento de toque)
Do ponto de vista geral, o fluxo do evento de toque começa no
Activity
, depois flui para o layout (dos layouts pai e filho) e depois para as visualizações. (Fluxo LTR na figura a seguir)Quando o evento de toque atinge o ponto de vista alvo, a visão pode manipular o evento então decidir para passá-lo para a esquemas anteriores / actividade ou não (voltando
false
detrue
noonTouch
método). (Fluxo RTL na figura acima)Agora, vamos dar uma olhada no código-fonte do View para obter uma visão mais profunda dos fluxos de eventos de toque. Examinando a implementação do
dispatchTouchEvent
, veríamos que, se você definir umOnTouchListener
para a visualização e depois retornartrue
em seuonTouch
método,onTouchEvent
a visualização não será chamada.Agora, observe o
onTouchEvent
método em que está a ação do eventoMotionEvent.ACTION_UP
. Vemos que a ação de executar clique acontece lá. Portanto, retornartrue
noOnTouchListener
'sonTouch
e, consequentemente, não chamar oonTouchEvent
, causa não chamar oOnClickListener
' sonClick
.Há outro problema em não chamar o
onTouchEvent
, que está relacionado ao estado pressionado e você mencionou na pergunta. Como podemos ver no bloco de código abaixo, há uma instânciaUnsetPressedState
dessas chamadas quando executadas. O resultado da não chamada é que a visualização fica presa no estado pressionado e seu estado de extração não muda.setPressed
(false)
setPressed(false)
UnsetPressedState :
Com relação às descrições acima, você pode alterar o código chamando a
setPressed(false)
si mesmo para alterar o estado desenhável em que a ação do evento éMotionEvent.ACTION_UP
:fonte
Now, look at the onTouchEvent method where the event action is MotionEvent.ACTION_UP. We see that perform-click action happens there. So, returning true in the OnTouchListener's onTouch and consequently not calling the onTouchEvent, causes not calling the OnClickListener's onClick.
No meu caso, o onClick é chamado. O mUnsetPressedState verifica se é nulo antes de definir como false e também o executável não tem certeza se será pré-pressionado. Eu não entendo muito bem como você deduzir que ele deve ser definido como falsoonClick
é chamado porque você está chamandov.performClick();
. Por favor, verifique o código acima naMotionEvent.ACTION_UP
seção novamente,setPressed(false)
é chamado assim mesmo, sejamUnsetPressedState
nulo ou não,prepressed
verdadeiro ou não. A diferença está na maneira de ligarsetPressed(false)
que pode ser atravéspost
/postDelayed
ou diretamente.Você está brincando
touch
efocus
eventos. Vamos começar com a compreensão do comportamento da mesma cor. Por padrão, éSelector
atribuído como plano de fundo aoButton
Android. Então, simplesmente alterando a cor de fundo, make é estático (a cor não muda). Mas não é um comportamento nativo.Selector
pode parecer com este.Como você pode ver acima, há estado
focused
e estadopressed
. Ao definir,onTouchListener
você manipulará os eventos de toque, que não têm nada a verfocus
.Selector
do botão deve substituir ofocus
eventotouch
durante o evento de clique no botão. Mas na primeira parte do seu código, você interceptou eventos para otouch
(retornando true do retorno de chamada). A mudança de cor não pode prosseguir e está congelando com a mesma cor. E é por isso que a segunda variante (sem interceptação) está funcionando bem e essa é a sua confusão.ATUALIZAR
Tudo que você precisa fazer é mudar o comportamento e a cor do
Selector
. Por ex. usando o próximo plano de fundo para oButton
. E removaonTouchListener
da sua implementação.fonte
onTouchListener
s quiser. Você só não precisa consumir evento porreturn true
.backgroundColor
.se você atribuir um plano de fundo ao botão, ele não mudará a cor ao clicar.
e defina-o como background para o seu botão
fonte
você pode apenas usar chips de material para, em vez da exibição de botão. consulte: https://material.io/develop/android/components/chip, onde eles lidam com esses eventos avançados e você pode personalizar com a aplicação dos temas.
fonte