Tenho uma tela com algumas abas. Cada aba possui vários TextViews.
Nesta tela o usuário deve conseguir alternar entre as abas com o movimento de arrastar o dedo para direita ou esquerda na tela.
Para isso, criei meu GestureDetector:
private class AlteraAbaGestureDetector implements OnGestureListener {
//...
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//...
//altero a aba que está sendo exibida.
return true;
}
}
Na minha Atividade, sobrescrevi o método onTouch:
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mGestureDetector == null) {
mGestureDetector = new GestureDetector(new AlteraAbaGestureDetector());
}
return mGestureDetector.onTouchEvent(event);
}
Meu problema é que o metódo onTouchEvent da minha atividade só é chamado quando deslizo o dedo sobre uma área sem TextViews.
Se faço o mesmo movimento sobre os textviews, me parece que eles “consomem” o evento e não o passam para a atividade.
Fiz um teste e adicionei o seguinte listener para alguns textViews:
textView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
v.onTouchEvent(event);
return AbasActivity.this.onTouchEvent(event); //redireciono o evento para minha atividade
}
});
Adicionado esse listener aos TextViews, resolve o problema, mas não quero adicionar um listener para TODOS eles, um por um.
Existe alguma maneira de tratar o evento onTouch independente se ele qual view foi “disparado”??
mas assim eu teria que criar minha própria ViewGroup?
Por enquanto, estou usando a seguinte solução:
criei um metódo que atribui o listener para todas a views filhas da minha view root:
protected void atribuiOnTouchListener(View view, OnTouchListener listener) {
if (view != null) {
view.setOnTouchListener(listener);
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
int childs = group.getChildCount();
for (int index = 0; index < childs; index++) {
atribuiOnTouchListener(group.getChildAt(index), listener);
}
}
}
}
resolveu meu problema de uma forma simples e limpa.
Mas gostaria de entender como funciona o despacho dos eventos na tela.
Pelo meus testes, o evento é sempre passado para as views “filhas”, e caso ela não
trate o evento, é passado para a View “pai”. É isso mesmo?
Por que o método Activity.onTouchEvent() só é chamado quando o evento é feito sobre uma área vazia de layout, sem Views?
Procurei no google artigos que abordem especificamente como o Android despacha os eventos de Motion, mas não achei. Se tiver algum link que
possa me passar, agradeço.
Eu também não tenho links, fui descobrindo fuçando.
Mas é mais ou menos o seguinte, um evento vai para o dispatchTouchEvent da View que está mais acima, ela que vai dispachando os eventos para os filhos. Se um filho consumir o evento os proximos eventos serão enviados para ele, se ele não consumir (retornar false no onTouch) os eventos não irão mais chegar nele.
O interceptTouchEvent para ViewGroup é que a qualquer momento o pai pode consumir os eventos que estão sendo enviados para os filhos.
Na solução que estou criando aqui no trabalho tive que reescrever esses tres métodos de tratamento de eventos de motion para fazer o que eu queria.