gpt4 book ai didi

android - 处理具有可选文本的 ClickableSpan 的点击需要双击

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:22:30 26 4
gpt4 key购买 nike

我有一个 TextView,其中每个单词都是一个 ClickableSpan。单击时,该词变为粗体,该词的字典定义显示在另一个TextView 中。在我使 TextView 中的文本可选择之前,该应用程序可以正常工作。当文本可选择时,定义会在点击时显示,但单词只有在双击时才显示为粗体。双击或长按选中文本(但长按不会使单词变为粗体)。

我的猜测是这个问题与 Action 处理过程中绘制状态更新的时间有关,但我无法找到修复方法。我尝试设置 TextView focusable="false" 但没有任何改变。相关代码如下。

curSpan = new WordSpan(index) {
@Override
public void onClick(View view) {
handleWordClick(index,this); // handles code to display definition
setMarking(true);
view.invalidate();
tvText.invalidate();
}
};

spannableStringBuilder.setSpan(curSpan, totalLength, totalLength + strWord, Spanned.SPAN_COMPOSING);

还有 WordSpan 定义:

class WordSpan extends ClickableSpan
{
int id;
private boolean marking = false;

public WordSpan(int id) {
this.id = id;
}

@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(Color.BLACK);
ds.setUnderlineText(false);
if (marking) {
ds.setTypeface(Typeface.create(myFont,Typeface.BOLD));
}
}

@Override
public void onClick(View v) {}

public void setMarking(boolean m) {
marking = m;
}
}

设置TextView的移动方式:

private MovementMethod createMovementMethod ( Context context ) {
final GestureDetector detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp ( MotionEvent e ) {
return true;
}

@Override
public boolean onSingleTapConfirmed ( MotionEvent e ) {
return true;
}
});

return new ScrollingMovementMethod() {

@Override
public boolean canSelectArbitrarily () {
return true;
}

@Override
public void initialize(TextView widget, Spannable text) {
Selection.setSelection(text, text.length());
}

@Override
public void onTakeFocus(TextView view, Spannable text, int dir) {
if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) {
if (view.getLayout() == null) {
// This shouldn't be null, but do something sensible if it is.
Selection.setSelection(text, text.length());
}
} else {
Selection.setSelection(text, text.length());
}
}

@Override
public boolean onTouchEvent ( TextView widget, Spannable buffer, MotionEvent event ) {
// check if event is a single tab
boolean isClickEvent = detector.onTouchEvent(event);

// detect span that was clicked
if (isClickEvent) {
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);

WordSpan[] link = buffer.getSpans(off, off, WordSpan.class);

if (link.length != 0) {
// execute click only for first clickable span
// can be a for each loop to execute every one
if (event.getAction() == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
return true;
}
}

// let scroll movement handle the touch
return super.onTouchEvent(widget, buffer, event);
}
};
}

编辑:我刚刚发现了一个可能有助于解决的新怪癖。如果我双击但在两次点击之间更改单词(点击一个单词然后快速点击另一个单词),第一次点击会显示该单词的定义,第二次点击第一个单词是粗体但第二个单词被选中(突出显示) ) 并且仍然显示第一个单词的定义。

So for example if I double tap "first" and then "second", when I click "first" the definition for "first" will be shown, and when I touch "second" the word "first" is bold and the word "second" is highlighted but the definition does not change (still showing definition for "first").

最佳答案

createMovementMethod 替换为以下内容。如果您遇到错误,请修复它并编辑此答案。

private MovementMethod createMovementMethod (final Context context ) {

return new ScrollingMovementMethod() {
public MotionEvent event;
public Spannable buffer;
public TextView widget;
final GestureDetector detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp ( MotionEvent e ) {

return true;
}

@Override
public boolean onSingleTapConfirmed ( MotionEvent e ) {
triggerClick();
return true;
}

@Override
public boolean onDoubleTap(MotionEvent e) {
triggerClick();
return true;
}

private boolean triggerClick() {
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);

WordSpan[] link = buffer.getSpans(off, off, WordSpan.class);

if (link.length != 0) {
// execute click only for first clickable span
// can be a for each loop to execute every one
if (event.getAction() == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
return true;
}

return true;
}
});
@Override
public boolean canSelectArbitrarily () {
return true;
}

@Override
public void initialize(TextView widget, Spannable text) {
Selection.setSelection(text, text.length());
}

@Override
public void onTakeFocus(TextView view, Spannable text, int dir) {
if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) {
if (view.getLayout() == null) {
// This shouldn't be null, but do something sensible if it is.
Selection.setSelection(text, text.length());
}
} else {
Selection.setSelection(text, text.length());
}
}

@Override
public boolean onTouchEvent (TextView widget, Spannable buffer, MotionEvent event ) {
// check if event is a single tab
boolean isClickEvent = detector.onTouchEvent(event);

//record this for GestureDetector
this.widget = widget;
this.buffer = buffer;
this.event = event;

// detect span that was clicked
if (isClickEvent) {
//ignore click here
return true;
}

// let scroll movement handle the touch
return super.onTouchEvent(widget, buffer, event);
}
};
}

关于android - 处理具有可选文本的 ClickableSpan 的点击需要双击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40709749/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com