#java #android #gesturedetector
#java #Android #gesturedetector
Вопрос:
Я настроил свою активность так, чтобы в ней был gestureDetectorCompat, который обнаруживает прокрутки влево и вправо, но в моей активности также есть горизонтальный RecyclerView.
Когда я пытаюсь прокрутить действие RecyclerView, getsureDetector также срабатывает, что нежелательно.
Вот код, связанный с GestureDetector, если это поможет.
private GestureDetectorCompat mDetector;
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;
mDetector = new GestureDetectorCompat(this, new SwipeDetector());
public boolean onTouchEvent(MotionEvent event){
this.mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
public boolean dispatchTouchEvent(MotionEvent ev){
if (mDetector != null){
if (mDetector.onTouchEvent(ev)){
return true;
}
}
return super.dispatchTouchEvent(ev);
}
public class SwipeDetector extends GestureDetector.SimpleOnGestureListener{
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY){
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH){
return false;
}
if( e2.getX() > e1.getX() ){
if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE amp;amp; Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY){
Left();
return true;
}
}
if( e1.getX() > e2.getX() ){
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE amp;amp; Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY){
Right();
return true;
}
}
return false;
}
}
Ответ №1:
Чтобы запускать только события RecyclerView
касания, не передавая их обратно родительским представлениям, вам нужно «использовать» это событие, возвращая true в соответствующих методах касания, например:
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true; //consume touch event
}
});
Кроме того, удалите вызов onTouchEvent()
внутри вашего родительского представления (activity), dispatchTouchEvent
чтобы он не запускал событие касания до того, как событие касания будет распространено на его дочерние представления (в вашем случае, the RecyclerView
) и будет использовано.
В качестве альтернативы, вы можете перехватывать все передаваемые события касания RecyclerView
и обрабатывать их самостоятельно (например, использовать их условно), переопределяя onInterceptTouchEvent
в прослушивателе элементов RecyclerView. Это полезно, когда вам также приходится иметь дело с дочерними представлениями внутри RecyclerView
и хотите условно разрешить дочерним представлениям получать или не получать события касания (отправляя их). Примером может быть что-то вроде этого:
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener(){
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
return true;
}
@Override
public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
Вы также можете иметь более точный контроль над тем, когда перехватывать события, а когда нет, проверяя действие входящего события / recyclerview
состояния касания и возвращая true для использования или false для передачи другим родительским представлениям. Например:
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN amp;amp; rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
Log.d(TAG, "onInterceptTouchEvent: click performed");
rv.findChildViewUnder(e.getX(), e.getY()).performClick();
return true;
}
return false;
}
Комментарии:
1. На самом деле я не касался событий касания recyclerview, поэтому они используются по умолчанию, мне нужно прокручивать его только тогда, когда элементов больше, чем места, чтобы показывать их, как это происходит по умолчанию. Могу ли я каким-то образом избежать перезаписи этой функциональности или я должен просто @Переопределить ее и скопировать вставленный код по умолчанию и изменить return false (который, я полагаю, есть), чтобы вернуть true?
2. Если вы оставите
onTouchEvent
поле пустым, я думаю, что поведение по умолчанию останется. Все, что вам нужно сделать, это изменить поведениеonInterceptTouchEvent
3. что вы подразумеваете под «кодом по умолчанию»? у вас есть другой код для событий касания вашего RecyclerView? Если да, то что вы используете, вы, вероятно, все равно можете переопределить
onInterceptTouchEvent
, но это где-то в другом месте. Однако, если у вас нет другого кода, измените значение по умолчаниюonInterceptTouchEvent
и оставьте все остальные методы в покое, все должно быть в порядке4. В принципе, если у вас нет никакого кода для работы с RecyclerViews, то что-то вроде примера в моем ответе должно работать нормально, и все поведение по умолчанию не должно быть изменено (за исключением использования события, конечно).
5. Я имел в виду посмотреть, как это делается по умолчанию, и просто скопировать, вставив это и изменив. Нет, никакого другого кода, на самом деле, это очень простой RecyclerView. В любом случае то, что вы говорите, выглядит именно так, как мне нужно, но я попытался установить
onInterceptTouchEvent
return true
значение, и теперь оно вообще не будет прокручиваться, установив его наfalse
позволяет мне прокручиватьRecyclerView
, поэтому функциональность все еще существует