Intereting Posts
Обнаруживать, когда он носит подключенный / отключенный к / с телефона Android Как я могу отобразить диалоговое окно над клавиатурой AlarmManager не работает Android, используя SimpleCursorAdapter для установки цвета не только строк Ошибка. Редактирование инструментов сборки SDK (23.0.3) слишком мало для проекта «Приложение». Минимальное значение – 25.0.0 Как определить тип файла MIME в android? Как изменить версию Android и номер версии кода в Android Studio? Запросы HTTP HTTP, работающие в симуляторе, но не на изнаночном устройстве Как запустить приложение Android в устройстве? Android set edit text style глобально в теме не работает Android-эмулятор все еще медленный, как черт, даже с изображением Intel, почему? Элемент прокрутки элемента ListView («UIKit Dynamics») Структура приложений Android: DLC через биллинг в приложении Как получить строку из разных локалей в Android? Как обмениваться сообщениями с google plus без приложения «Google Plus», установленного на устройстве

Самый верхний просмотр событий ласточек, поскольку перекрытие

Итак, вот моя структура макета:

- RelativeLayout (full screen) - FrameLayout (full screen) - Button (in the middle of the screen) - RecyclerView (align parent bottom but with very big padding top to capture the scrolling also in the top of the screen, so it's basically acting like a full screen `RecyclerView`) 

Так что да, взгляды перекрывают друг друга.

По причине того, что RecyclerView является самым верхним видом, он захватывает все сенсорные события на экране и проглатывает их, не позволяя любым касаниям «пройти через него» к основным представлениям ниже. (Примечание: по основным представлениям я не имею в виду детей RecyclerView , кроме детей другого rootview's )

Я прочитал множество сообщений stackoverflow, касающихся распространения событий касания и предотвращения проглатывания событий касания и т. Д., И хотя это кажется довольно простой задачей для выполнения, я не мог добиться следующего эффекта:

Я хочу, чтобы мой RecyclerView захватил событие касания, поэтому он будет прокручиваться или что угодно. Но я хочу, чтобы rootView считал, что RecyclerView не захватил это событие и продолжает передавать его другим rootview (детям rootview ).

Вот что я пытался сделать:

1 . Переопределяя dispatchTouchEvent RecyclerView чтобы выполнить свою логику и вернуть false, чтобы действовать, поскольку оно не отправило его событие касания, поэтому rootview будет продолжать итерацию при касании через свои дочерние представления.

 @Override public boolean dispatchTouchEvent(MotionEvent ev) { super.dispatchTouchEvent(ev); return false; } 

Что случилось:

RecyclerView все еще функционирует, но все еще проглатывает все события касания (точно так же, как и раньше)

2 . Переопределение onTouchEvent RecyclerView для выполнения своей логики и возврата false. (Примечание: я знаю, что это не похоже на решение, но я попытался)

 @Override public boolean onTouchEvent(MotionEvent e) { super.onTouchEvent(e); return false; } 

Что случилось:

Тот же результат, что и в # 1

Я сделал несколько ухищрений с той же идеей, но они тоже не сработали, так что я сейчас немного любезно и хотел бы помочь вам, ребята!

У меня есть два предложения для вас:
Первое проще, но предполагает, что вы хотите щелкнуть по Button и она может появиться над RecyclerView , если это так, вы можете просто изменить порядок макета:

 - RelativeLayout (full screen) - FrameLayout (full screen) - RecyclerView - Button (in the middle of the screen) 

Если вам нужно что-то более общее, тогда это можно сделать следующим образом:

 recyclerView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int [] pos = new int[2]; recyclerView.getLocationOnScreen(pos); Rect rect = new Rect(); button.getHitRect(rect); if (rect.contains((int) event.getX() + pos[0], (int) event.getY() + pos[1])) { button.onTouchEvent(event); } return false; } }); 

Вам нужно будет обрабатывать все ваши взгляды отдельно, что не так приятно, но оно работает в моем тесте.

Примечание. Если вы добавили addOnItemTouchListener в свой RecyclerView вам нужно будет добавить указанную функциональность в onInterceptTouchEvent (или в оба места, в зависимости от ваших элементов и RecyclerView ).

Я не уверен, насколько это эффективное / правильное / приятное решение, но вот что мне приходит в голову: что, если вы слушаете события касания в корневом представлении ( RelativeLayout в вашем случае) и отправляете событие касания ко всем Дети этого макета, за исключением RecyclerView ?

 public class MyRelativeLayout extends RelativeLayout { ... @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final boolean intercept = super.onInterceptTouchEvent(ev); // getChildCount() - 1, because `RecyclerView` is the last child for (int i = 0, size = getChildCount() - 1; i < size; i++) { View v = getChildAt(i); v.dispatchTouchEvent(MotionEvent.obtain(ev)); } return intercept; } } 

Кажется, это должно сработать.

Я не совсем понимаю вашу проблему, однако, если цель состоит в том, чтобы не разрешать RecyclerView потреблять любые и все события касания, тогда просто установите android:elevation="1dp" для FrameLayout и Override dispatchTouchEvent() следующим образом:

 @Override public boolean dispatchTouchEvent(MotionEvent event) { Logger.log("CustomFrameLayout : dispatchTouchEvent"); boolean result = super.dispatchTouchEvent(event); ((View) getParent()).findViewById(R.id.recyclerView).dispatchTouchEvent(event); return result; // This part can be changed according to requirement. } 

Это может иметь или не иметь нежелательных побочных эффектов, так как я просто придумал это самостоятельно, однако, насколько я проверял, это не так.

Случаи, которые я тестировал:

  1. Прокрутка в RecyclerView: работает.
  2. Клики в элементах RecyclerView: работают.
  3. Клики в Children of FrameLayout: работают.

ОБНОВИТЬ :

Почему существует необходимость в повышении для FrameLayout?

android:elevation обеспечивает средство для положения оси z любого макета. Что касается того, почему есть необходимость сделать это, чтобы ответить, что мне придется углубиться глубже и дать вам длинное объяснение (на нем уже загружено множество материалов), достаточно сказать, что MotionEvent s просачивается вниз. Основные правила: от корня до его детей. Сначала ребенок, чтобы сначала получить событие (проверить, принадлежит ли это событие), просачивается по их позиции по оси xy, а затем по порядку по оси z (вверху Один получает событие первым).


Итак, в вашем случае, когда обнаружен MotionEvent он передается в RelativeLayout (RootView), у которого есть 3 ребенка, Button будет отфильтрована из-за положения. Теперь у вас есть 2 FrameLayout и RecyclerView . Самый младший ребенок RelativeLayout находится поверх оси z , что означает, что событие RecyclerView будет отправлено ему первым (что естественно будет потреблять событие). Если, однако, возник случай, когда событие не было израсходовано (ваша первая попытка), событие будет передано следующему дочернему View до тех пор, пока не будет больше дочернего View s слева, в этот момент родительский ( RelativeLayout ) примет событие Принадлежит самому себе и называет его onInterceptTouchEvent() . Во время этого процесса, если View поглотил событие, все последующие вызовы будут переданы ему напрямую (причина, по которой вы можете сделать только одну из двух FrameLayout или RecyclerView ).

Все приведенное выше объяснение означает, что в книге правил только один View будет когда-либо потреблять event .

Что я сделал

Я просто поднял FrameLayout чтобы он был официальным получателем события. Переопределите dispatchTouchEvent() и отправите одно и то же событие в соседний RecyclerView , который считает, что событие было доведено до него обычным режимом.

Теперь после всего этого объяснения

Комментарий // Эта часть может быть изменена в соответствии с требованием.

Лучшим и, возможно, методом без ошибок было бы

 boolean result2 = ((View) getParent()).findViewById(R.id.recyclerView).dispatchTouchEvent(event); return result || result2; 

Поэтому, если какой-либо из Views потребляет событие, корневой элемент будет считать, что он тоже был потреблен.