EditText 中的 ClickableSpan 到文本末尾调用 click() 到行尾
ClickableSpan in the EditText to the end of text calls click() to the end of line
我有一个 EditText 和 TextWatcher,我在其中检查模式以确定在何处创建 ClickableSpans。
private void checkSpans(){
Matcher matcher = Pattern.compile("(^|[ \t\n])#\w+").matcher(text);
while (matcher.find()) {
BlueClickableSpan[] spans = getText().getSpans(matcher.start(), matcher.end(), BlueClickableSpan.class);
for (BlueClickableSpan span : spans) {
text.removeSpan(span);
}
text.setSpan(new BlueClickableSpan(),
matcher.start(),
matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
这是我的自定义 Span class。
private class BlueClickableSpan extends ClickableSpan {
@Override
public void onClick(View view) {
Spanned s = getText();
int start = s.getSpanStart(this);
int end = s.getSpanEnd(this);
String clickedString = s.subSequence(start, end).toString().trim();
if (onSpanClick != null)
onSpanClick.onClick(clickedString);
}
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(ContextCompat.getColor(IdeaFlowApp.getAppContext(), R.color.main_blue));
}
}
问题是,当我以 span 结束我的文本并且它后面没有字符并且我在它之后点击时,它仍然算作对 span 的点击并调用 onClick。因此,我不能将光标放在 span 之后继续编辑。但是如果我打印任何符号,甚至是跨度后面的空格,我可以很容易地将光标放在跨度之后,一切正常。如果没有超出可点击范围的符号,是否有任何方法可以修复编辑文本中的点击?
我在 dor506s answer here 中找到了解决问题的方法。
但是对于带有 span 的多行文本有一些问题,所以我做了一些调整:
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 = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
int lineLength = line;
String[] lines = getText().toString().split("\n");
for (int i = 0; i <= line; i++) {
lineLength += lines[i].length();
}
if (off >= lineLength) {
// Return true so click won't be triggered in the leftover empty space
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
也许不是最漂亮的多行解决方案,但它对我有用。
我有一个 EditText 和 TextWatcher,我在其中检查模式以确定在何处创建 ClickableSpans。
private void checkSpans(){
Matcher matcher = Pattern.compile("(^|[ \t\n])#\w+").matcher(text);
while (matcher.find()) {
BlueClickableSpan[] spans = getText().getSpans(matcher.start(), matcher.end(), BlueClickableSpan.class);
for (BlueClickableSpan span : spans) {
text.removeSpan(span);
}
text.setSpan(new BlueClickableSpan(),
matcher.start(),
matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
这是我的自定义 Span class。
private class BlueClickableSpan extends ClickableSpan {
@Override
public void onClick(View view) {
Spanned s = getText();
int start = s.getSpanStart(this);
int end = s.getSpanEnd(this);
String clickedString = s.subSequence(start, end).toString().trim();
if (onSpanClick != null)
onSpanClick.onClick(clickedString);
}
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(ContextCompat.getColor(IdeaFlowApp.getAppContext(), R.color.main_blue));
}
}
问题是,当我以 span 结束我的文本并且它后面没有字符并且我在它之后点击时,它仍然算作对 span 的点击并调用 onClick。因此,我不能将光标放在 span 之后继续编辑。但是如果我打印任何符号,甚至是跨度后面的空格,我可以很容易地将光标放在跨度之后,一切正常。如果没有超出可点击范围的符号,是否有任何方法可以修复编辑文本中的点击?
我在 dor506s answer here 中找到了解决问题的方法。 但是对于带有 span 的多行文本有一些问题,所以我做了一些调整:
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 = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
int lineLength = line;
String[] lines = getText().toString().split("\n");
for (int i = 0; i <= line; i++) {
lineLength += lines[i].length();
}
if (off >= lineLength) {
// Return true so click won't be triggered in the leftover empty space
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
也许不是最漂亮的多行解决方案,但它对我有用。