Первый ответ на ваш вопрос заключается в том, что вы не устанавливаете прослушиватель кликов в своем TextView, который потребляет события click, как указывает пользователь2558882. После того, как вы установите прослушиватель кликов в TextView, вы увидите, что области, находящиеся за пределами сенсорной зоны ClickableSpans, будут работать должным образом. Тем не менее, вы обнаружите, что когда вы нажмете на один из ваших ClickableSpans, обратный вызов onClick TextView также будет запущен. Это приводит нас к сложной проблеме, если для вас есть проблема с огнем. Ответ пользователя2558882 не может гарантировать, что ваш обратный вызов onClick ClickableSpan будет запущен перед вашим TextView. Вот некоторые решения от a similar thread, которые лучше реализованы и объяснение от источника. Принятый ответ, что поток должен работать на большинстве устройств, но комментарии для этого ответа указывают на некоторые устройства, имеющие проблемы. Похоже, что некоторые устройства с пользовательскими интерфейсами пользовательских интерфейсов/изготовителей виноваты, но это спекуляция.
Так почему бы вам не гарантировать заказ обратного вызова onClick? Если вы посмотрите на источник TextView (Android 4.3), вы заметите, что в методе onTouchEvent boolean superResult = super.onTouchEvent(event);
(super is View) вызывается до handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
, который является вызовом вашего метода перемещения, который затем вызывает ваш ClickClick onClick. Взгляните на супер (View) onTouchEvent (..), Вы заметите:
// Use a Runnable and post this rather than
// performClick directly. This lets other visual
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) { // <---- In the case that this won't post,
performClick(); // it'll fallback to calling it directly
}
performClick() вызывает набор нажмите слушателю, который в данном случае является щелчок слушатель нашей TextView в. Это означает, что вы не будете знать, в каком порядке будут срабатывать ваши обратные вызовы onClick. То, что вы знаете, заключается в том, что ваши вызовы ClickableSpan и TextView будут вызваны. Решение по потоку, о котором я упоминал ранее, помогает обеспечить порядок, чтобы вы могли использовать флаги.
Если обеспечение совместимости с большим количеством устройств является приоритетом, вам лучше всего воспользоваться вторым взглядом на ваш макет, чтобы увидеть, можете ли вы избежать застревания в этой ситуации. Как правило, есть много вариантов компоновки, чтобы обойти такие случаи.
Редактировать для комментариев ответа:
Когда TextView выполняет onTouchEvent, он вызывает onTouchEvent вашего LinkMovementMethod, так что он может обрабатывать вызовы методов OnClick различного ClickableSpan в. Ваш LinkMovementMethod выполняет следующие действия в onTouchEvent:
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
return true;
} else {
Selection.removeSelection(buffer);
}
}
return super.onTouchEvent(widget, buffer, event);
}
Вы заметите, что он принимает MotionEvent, получает действие (ACTION_UP: поднимая палец, ACTION_DOWN: нажимая на палец), х и у координаты, где touch, а затем находит, какой номер строки и смещение (позиция в тексте) касание. Наконец, если есть ClickableSpans, которые охватывают эту точку, они извлекаются и вызывается их методы onClick. Поскольку мы хотим передать любые прикосновения к вашему макету родителя, вы можете либо вызвать свои макеты onTouchEvent, если хотите, чтобы он делал все, что он делает, когда прикасался, или вы могли бы назвать его клише-слушателем, если это реализует ваши необходимые функции. Вот где сделать, что:
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
return true;
} else {
Selection.removeSelection(buffer);
// Your call to your layout's onTouchEvent or it's
//onClick listener depending on your needs
}
}
Так обзор, вы будете создавать новый класс, который расширяет LinkMovementMethod, переопределить это onTouchEvent метод, скопируйте и вставьте этот источник с вашими звонками в правильном положении, когда я комментировал, обеспечить вы настраиваете метод перемещения TextView на этот новый подкласс, и вы должны быть установлены.
Edited снова для возможного избежания побочных эффектов Посмотрите на источник ScrollingMovementMethod (в родительском LinkMovementMethod), и вы увидите, что это метод делегата, который вызывает статический метод return Touch.onTouchEvent(widget, buffer, event);
Это означает, что вы можете просто добавить, что, как ваш последней строки в методе и избежать вызова функции super (LinkMovementMethod's) onTouchEvent, которая будет дублировать то, что вы вставляете, а другие события могут провалиться, как ожидалось.
и ваши проблемы есть? – Pragnani
Когда я нажимаю на TextView за пределами ClickableSpan, сообщение «всего макета» не появляется. Я должен это сделать. –
Установите ширину и высоту 'match_parent' вместо' wrap_content' – Pragnani