ClickableSpan странное поведение:onClick() вызывается при нажатии на пустое место
У меня есть TextView
с ClickableSpan
тем, что layout_height и layout_width - это wrap_content.
Когда текст в TextView
в не слишком долго, он работает нормально. Когда текст настолько длинный, что занимает 2 строки, он также работает нормально, но имеет странное поведение.
Именно тогда я нажал на пустое место второй строки (пока не заполнить текстом, но часть TextView
), ClickableSpan
onClick()
обратный вызов называется.
Я не ожидаю этого, так как щелкнул только по пустому пространству, но не по расширенному тексту. Хотя это не сильно влияет, я хочу знать, что позади.
Я установил ClickableSpan
с кодом ниже:
TextView tv = (TextView) findViewById(R.id.text);
tv.setText("TEXT TEXT TEXT TEXT");
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(tv.getText());
ssb.setSpan(new TestClickableSpan(), ssb.length()-5, ssb.length(), 0);
tv.setText(ssb);
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setOnTouchListener(new TextViewOnTouchListener());
TextViewOnTouchListener:
class TextViewOnTouchListener implements OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TextView", "onTouch");
return false;
}
}
TestClickableSpan:
class TestClickableSpan extends ClickableSpan{
@Override
public void onClick(View arg0) {
Log.d("ClickableSpan", "Confirm OnClick: "+arg0.toString());
}
}
1 ответ
Мне удалось решить ее, расширив LinkMovementMethod и проверив, равно ли смещение события касания или больше, чем длина текста:
public class MovementMethod extends LinkMovementMethod {
@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);
if (off >= widget.getText().length()) {
// Return true so click won't be triggered in the leftover empty space
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
Спасибо @dor506 за ответ, но он не работает на гравитацию center
, Я немного изменил.
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
y -= widget.getTotalPaddingTop();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
float lineLeft = layout.getLineLeft(line);
float lineRight = layout.getLineRight(line);
if (x > lineRight || (x >= 0 && x < lineLeft)) {
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
Ответ dor506 отлично сработал для меня для EditTexts с одной строкой. Однако, когда пользователь набрал несколько строк, решение будет применяться только к последней строке. То есть ClickableSpans в нижней строке будет вести себя должным образом, но во всех других строках будет щелкать через пробел.
Я решил это, изменив:
if (off >= widget.getText().length()) {
// Return true so click won't be triggered in the leftover empty space
return true;
}
чтобы:
if (off >= layout.getLineVisibleEnd(line)) {
// Return true so click won't be triggered in the leftover empty space
return true;
}
(Извините за публикацию в качестве отдельного ответа - у меня недостаточно репутации, чтобы добавить комментарий, но я подумал, что это может стоить документирования!)