Идея Марага об отправке dispatchTouchEvent () из onLongClick () казалась многообещающей, но вам пришлось бы создать объект события для отправки в dispatchTouchEvent (), чтобы имитировать событие, использованное OnLongClickListener.
Я перевернул это, чтобы перехватить событие касания в родительском представлении, а затем перенаправить его в дочернее представление. Я подклассифицировал родительское представление, затем добавил этот метод:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// this allows us to catch touch events on the list view if a child button is in the same location, then pass them on to child buttons so they can use them, too
// we don't have to worry about move events because currently none of the child buttons use them
int touchX = Math.round(event.getX());
int touchY = Math.round(event.getY());
Rect touchRect = new Rect(touchX, touchY, touchX, touchY);
Log.d("onInterceptTouchEvent", "got touch at " + touchRect);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
for (View cell : ViewUtils.getSubviews(this)) {
int cellX = Math.round(cell.getX());
int cellY = Math.round(cell.getY());
Rect cellRect = new Rect(cellX, cellY, cellX + cell.getWidth(), cellY + cell.getHeight());
if (Rect.intersects(touchRect, cellRect)) {
for (View button : ViewUtils.getSubviews((ViewGroup) cell)) {
if (button instanceof ImageButton) {
int buttonX = Math.round(button.getX()) + cellX;
int buttonY = Math.round(button.getY()) + cellY;
Rect buttonRect = new Rect(buttonX, buttonY, buttonX + button.getWidth(), buttonY + button.getHeight());
Log.d("onInterceptTouchEvent", "found button at " + buttonRect);
if (Rect.intersects(touchRect, buttonRect)) {
Log.d("onInterceptTouchEvent", "forward touch to button");
button.dispatchTouchEvent(event);
break;
}
}
}
break;
}
}
break;
}
return true;
}
В моем случае родительское представление - это ListView, а дочерние представления - это кнопки ImageButtons внутри ячеек таблицы. Таким образом, этот код перебирает ячейки таблицы, затем кнопки в каждой ячейке, чтобы найти кнопку, которая соответствует местоположению касания, и передает касание этой кнопке. Все мои кнопки - это кнопки ImageButton, которые используют OnClickListener или OnLongClickListener, поэтому я не пересылаю события ACTION_MOVE, но вы можете при необходимости.
Вот метод getSubViews (), использованный выше:
public static ArrayList<View> getSubviews(ViewGroup viewGroup) {
ArrayList<View> subviews = new ArrayList<View>();
for (int i=0; i<viewGroup.getChildCount(); i++) {
subviews.add(viewGroup.getChildAt(i));
}
return subviews;
}
Обновление: более простая версия
Приведенный выше код должен работать для конкретной ситуации получения прикосновений к родительскому представлению и длительных нажатий на дочернем представлении. Но я обнаружил, что это не поддерживает регулярные клики в дочерних представлениях. Я думаю, что это связано с тем, что onInterceptTouchEvent () обрабатывает события ACTION_DOWN иначе, чем другие события. Документация для этого метода очень запутанная.
Однако вот более простой подход, который должен поддерживать все виды событий касания и нажатия в родительском или дочернем представлениях. Как и выше, это требует создания подкласса родительского представления. Также требуется установить метод onTouch непосредственно в этом классе, а не использовать setOnTouchListener () в другом классе:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
this.onTouch(this, event); // send the touch to the onTouch method below
return false; // then let the touch proceed to child buttons
// return true = this method and this view's onTouch receives events; return false = this method and children's onTouch receive events; remove this method = only children's onTouch receive events
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// work with this touch event here
return false; // then let the touch continue to other applicable views
// return true = only this view receives events; return false = this view and other applicable views receive events
}