Как передать событие onClick представления его родительскому элементу на Android?


100

У меня есть TextView в макете, чей фон является селектором. И текст TextView установлен на Spanned from HTML. Затем я установил TextView с помощью LinkMovementMethod.

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

Как это решить?

Ответы:


45

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

Activity.dispatchTouchEvent(MotionEvent) - Это позволяет вашей Activity перехватывать все события касания до того, как они будут отправлены в окно.

ViewGroup.onInterceptTouchEvent(MotionEvent) - Это позволяет ViewGroup отслеживать события по мере их отправки дочерним представлениям.

ViewParent.requestDisallowInterceptTouchEvent(boolean) - Вызовите это для родительского View, чтобы указать, что он не должен перехватывать события касания с onInterceptTouchEvent (MotionEvent).

Больше информации здесь .

Надеюсь, это поможет.


1
Есть ли более простой способ передать события для запуска onClick и onLongClick в родительском представлении, или мне нужно реализовать их самостоятельно?
Шиами

Проверьте это: stackoverflow.com/questions/2136696/pass-event-to-parent-view Возможно, вы захотите попробовать передать тот же прослушиватель кликов в другие экземпляры, как предлагается, хотя я не знаю, сработает ли он , но, возможно, стоит попробовать.
Луис Мигель Серрано,

Ответ ниже намного чище
JPM

Должен ли я создать экземпляр MotionEvent? Пожалуйста, объясните, @LuisMiguelSerrano
olegario

@olegario, обычно вы переопределяете метод, например, для dispatchTouchEvent, с помощью @Override, чтобы определить новое поведение для него, поэтому вы просто получаете событие движения, которое система предоставила вашему действию (или другому компоненту вашего приложения), и вы обрабатывать его и / или пересылать любому количеству дочерних компонентов в соответствии с вашими собственными правилами. Что-то вроде: @Override public boolean dispatchTouchEvent(MotionEvent ev) { ... }
Луис Мигель Серрано

214

Объявите, что вы TextViewне кликабельны / фокусируемы, используя android:clickable="false"и android:focusable="false"или v.setClickable(false)и v.setFocusable(false). События щелчка должны быть отправлены наTextView родительскому объекту.

Примечание:

Для этого вам нужно добавить щелчок в его директ parent. или установите android:clickable="false"и android:focusable="false"своему прямому родителю, чтобы передать слушателя следующему родителю .


1
О, чувак, если бы я мог дать это +100, я бы сделал это. Пытался выяснить, как сделать так, чтобы щелчок работал только в ViewPager, а не в макете адаптеров с TouchImageView, реализующим onTouch! Это решение сработало как шарм.
JPM

1
но что, если я хочу обработать событие изменения фокуса EditText?
SweetWisher ツ

2
Сценарий такой: у меня есть макет, который содержит текст редактирования, относительный макет, счетчик и представление списка. Я хочу запускать событие касания родительского макета всякий раз, когда я касаюсь любого места на экране, кроме текста редактирования и счетчика
SweetWisher ツ

9
Важно помнить, что если вы используете TextView#setOnClickListener()на TextView, он становится интерактивным, даже если он объявлен как android:clickable="false", и даже если для параметра ClickListenerустановлено значение null( setOnclickListener(null))
Кристиан Гарсия,

3
Интересный факт: если в TextView есть android:inputTypeатрибут, он будет молча потреблять события щелчка даже с clickable: false и focusable: false; в моем случае это было оформлено в стиле, и мне потребовалось 30 минут, чтобы выяснить причину.
Кирилл Кармазин

18

Иногда помогает только это:

View child = parent.findViewById(R.id.btnMoreText);
    child.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            View parent = (View) v.getParent();
            parent.performClick();
        }
    });

Другой вариант, работает не всегда:

child.setOnClickListener(null);

Это работало CardViewкак дочернее представление, поскольку, CardViewпохоже, игнорирует clickable="false"и focusable="false". Однако использование setOnTouchListenerи вызов onTouchEventродителя вместо этого позволяет ему отображать сенсорную обратную связь (например, эффект пульсации).
methodignature

Я разместил соответствующий код ниже: stackoverflow.com/a/52928884/5652513 .
methodignature

10

Ставить

android:duplicateParentState="true"

в дочернем элементе представления получают свое доступное для рисования состояние (сфокусировано, нажато и т. д.) от своего прямого родителя, а не от себя. вы можете установить onclick для родителя, и он вызовет нажатие дочернего элемента


OP хочет вызвать родительский прослушиватель кликов при нажатии дочернего элемента, а не наоборот.
Фарид

3

Если вы TextViewсоздаете проблемы с щелчком, удалите их android:inputType=""из XML-файла.


Если вы не знаете, почему, я рекомендую вам не делать этого. Просто говорю ... каждому свое.
dell116

Вы должны установить его наandroid:inputType="none"
AZ_

1

Этот ответ похож на ответ Александра Ухова , за исключением того, что он использует события касания, а не события щелчка. Эти события позволяют родителю отображать правильные состояния нажатия (например, эффект пульсации). Этот ответ также находится на Kotlin вместо Java.

view.setOnTouchListener { view, motionEvent ->
    (view.parent as View).onTouchEvent(motionEvent)
}

0

Если вы хотите, чтобы оба OnTouchи OnClickслушатель смотрели и на родителей, и на детей, используйте следующий трюк:

  1. Пользовательский ScrollView в качестве родительского представления и внутри него помещает дочернее представление в Relative / LinearLayout.

  2. Сделайте родительский ScrollView android:fillViewport="true"так, чтобы просмотр не прокручивался.

  3. Затем установите OnTouchслушателя на родительский и OnClickслушатель на дочерние представления. И наслаждайтесь обратными вызовами обоих слушателей.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.