Eu quero ter a detecção de gestos fling
funcionando no meu aplicativo Android.
O que eu tenho é um GridLayout
que contém 9 ImageView
s. A fonte pode ser encontrada aqui: [Romain Guys's Grid Layout][4].
Esse arquivo que eu pego é do Romain Guy's aplicativo Photostream e foi apenas ligeiramente adaptado.
Para a situação de clique simples eu preciso apenas definir o onClickListener
para cada ImageView
que eu adicionar para ser a principal atividade
que implementa o View.OnClickListener
. Parece infinitamente mais complicado implementar algo que reconheça um fling
. Eu presumo que isso seja porque pode abranger views
?
Se a minha actividade implementar OuvinteOnGestureIdentificador` Eu não sei'não sei como definir isso como o ouvinte de gestos para a "Grid" ou a "Imagem" que eu acrescente.
classe pública SelectFilterActivity estende Atividade implementa
View.OnClickListener, OnGestureListener { ...
Se a minha actividade implementar "OnTouchListener" então eu não tenho método "onFling" para "sobrepujar" (tem dois eventos como parâmetros que me permitem para determinar se o caso era digno de nota).
classe pública SelectFilterActivity estende Atividade implementa
View.OnClickListener, OnTouchListener { ...
Se eu fizer um View
personalizado, como GestureImageView
que estende o ImageView
I don'não sei como dizer à atividade que um fling
ocorreu a partir da visão. Em qualquer caso, eu tentei isso e os métodos não foram't chamados quando eu toquei na tela.
Eu realmente só preciso de um exemplo concreto disso funcionando através dos pontos de vista. O quê, quando e como eu devo anexar este "ouvinte"? Eu preciso ser capaz de detectar cliques únicos também.
// Gesture detection
mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
int dx = (int) (e2.getX() - e1.getX());
// don't accept the fling if it's too short
// as it may conflict with a button push
if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.absvelocityY)) {
if (velocityX > 0) {
moveRight();
} else {
moveLeft();
}
return true;
} else {
return false;
}
}
});
É possível colocar uma vista transparente sobre a parte superior do meu ecrã para captar os flings?
Se eu optar por não inflar
as minhas visualizações de imagens do XML, posso passar o GestureDetector
como parâmetro construtor para uma nova subclasse de ImageView
que eu crio?
Esta é a atividade muito simples para a qual a I'estou tentando fazer com que a detecção fling
funcione: SelectFilterActivity (Adaptado do photostream).
I'tenho estado a olhar para estas fontes:
Até agora nada funcionou para mim e eu esperava algumas dicas.
Graças ao Código Shogun, cujo código eu adaptei à minha situação.
Deixe a sua actividade implementarOnClickListener
como de costume:
public class SelectFilterActivity extends Activity implements OnClickListener {
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* ... */
// Gesture detection
gestureDetector = new GestureDetector(this, new MyGestureDetector());
gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
};
}
class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left swipe
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
// nothing
}
return false;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
}
}
Anexe seu ouvinte de gestos a todas as visualizações que você adicionar ao layout principal;
// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this);
imageView.setOnTouchListener(gestureListener);
Observe com admiração como os seus métodos anulados são atingidos, tanto o onClick(View v)
da actividade como o onFling
do ouvinte de gestos.
public void onClick(View v) {
Filter f = (Filter) v.getTag();
FilterFullscreenActivity.show(this, input, f);
}
A dança pós 'fling' é opcional, mas encorajada.
O código do detector de gestos acima é muito útil! Você pode, no entanto, desejar tornar esta densidade de solução agnóstica utilizando os seguintes valores relativos (REL_SWIPE)
em vez dos valores absolutos (SWIPE_)
DisplayMetrics dm = getResources().getDisplayMetrics();
int REL_SWIPE_MIN_DISTANCE = (int)(SWIPE_MIN_DISTANCE * dm.densityDpi / 160.0f);
int REL_SWIPE_MAX_OFF_PATH = (int)(SWIPE_MAX_OFF_PATH * dm.densityDpi / 160.0f);
int REL_SWIPE_THRESHOLD_VELOCITY = (int)(SWIPE_THRESHOLD_VELOCITY * dm.densityDpi / 160.0f);
Também como uma pequena melhoria.
A principal razão para o bloco de tentativa/ captura é que e1 poderia ser nulo para o movimento inicial. além da tentativa/ captura, incluir um teste para nulo e retorno. similar ao seguinte
if (e1 == null || e2 == null) return false;
try {
...
} catch (Exception e) {}
return false;