如何在 TextView 中获取 ClickableSpan 的坐标?

Posted

技术标签:

【中文标题】如何在 TextView 中获取 ClickableSpan 的坐标?【英文标题】:How get coordinate of a ClickableSpan inside a TextView? 【发布时间】:2012-08-07 23:33:06 【问题描述】:

我有一个TextView 和许多ClickableSpan

点击ClickableSpan时,我必须在屏幕上获取坐标(以在他的位置显示自定义View)。

问题是我不知道该怎么做。 ClickableSpanonClick() 方法在参数中为我提供了 ViewTextView 包含 ClickableSpan

我已使用以下方法获取 TextView 中的字符位置,但我不知道如何将其转换为获取文本屏幕上的 x/y 位置。

@Override
public void onClick(View v)

    SpannableString completeText = (SpannableString)((TextView) v).getText();
    Log.v("characters position", completeText.getSpanStart(this) + " / " + completeText.getSpanEnd(this));


提前感谢您的帮助!

编辑:我想获取 ClickableSpan 的整个坐标及其大小,目的是在文本的底部中心显示我的自定义视图。 onTouch 方法会给我手指位置,而不是整个文本坐标。所以,用这个方法,我就不会有中间的文字了。

【问题讨论】:

重写 onTouch() 并使用 event.getX(), event.getY()? 感谢您的回答!不幸的是,我发现这种方法非常……丑陋!我希望有更好的解决方案。此外,我忘记给出另一个精度:我想获得 ClickableSpan 的整个坐标及其大小,目的是在文本的底部中心显示我的自定义视图。 onTouch 方法会给我手指位置,而不是整个文本坐标。所以,用这个方法,我就不会有中间的文字了。还有其他想法吗? 【参考方案1】:

我找到了解决方案 :-) 在这里,也许这会帮助像我一样有同样问题的其他人!

// Initialize global value
this.parentTextViewRect = new Rect();
        
        
// Initialize values for the computing of clickedText position
SpannableString completeText = (SpannableString)(parentTextView).getText();
Layout textViewLayout = parentTextView.getLayout();
        
double startOffsetOfClickedText = completeText.getSpanStart(clickedText);
double endOffsetOfClickedText = completeText.getSpanEnd(clickedText);
double startXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int)startOffsetOfClickedText);
double endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int)endOffsetOfClickedText);
        
        
// Get the rectangle of the clicked text
int currentLineStartOffset = textViewLayout.getLineForOffset((int)startOffsetOfClickedText);
int currentLineEndOffset = textViewLayout.getLineForOffset((int)endOffsetOfClickedText);
boolean keywordIsInMultiLine = currentLineStartOffset != currentLineEndOffset;
textViewLayout.getLineBounds(currentLineStartOffset, this.parentTextViewRect);
        
        
// Update the rectangle position to his real position on screen
int[] parentTextViewLocation = 0,0;
parentTextView.getLocationOnScreen(parentTextViewLocation);
        
double parentTextViewTopAndBottomOffset = (
    parentTextViewLocation[1] - 
    parentTextView.getScrollY() + 
    this.parentTextView.getCompoundPaddingTop()
);
this.parentTextViewRect.top += parentTextViewTopAndBottomOffset;
this.parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;
        
// In the case of multi line text, we have to choose what rectangle take
if (keywordIsInMultiLine)
            
    int screenHeight = this.mWindowManager.getDefaultDisplay().getHeight();
    int dyTop = this.parentTextViewRect.top;
    int dyBottom = screenHeight - this.parentTextViewRect.bottom;
    boolean onTop = dyTop > dyBottom;
            
    if (onTop)
        endXCoordinatesOfClickedText = textViewLayout.getLineRight(currentLineStartOffset);
    
    else
        this.parentTextViewRect = new Rect();
        textViewLayout.getLineBounds(currentLineEndOffset, this.parentTextViewRect);
        this.parentTextViewRect.top += parentTextViewTopAndBottomOffset;
        this.parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;
        startXCoordinatesOfClickedText = textViewLayout.getLineLeft(currentLineEndOffset);
    
            

        
this.parentTextViewRect.left += (
    parentTextViewLocation[0] +
    startXCoordinatesOfClickedText + 
    this.parentTextView.getCompoundPaddingLeft() - 
    parentTextView.getScrollX()
);
this.parentTextViewRect.right = (int) (
    this.parentTextViewRect.left + 
    endXCoordinatesOfClickedText - 
    startXCoordinatesOfClickedText
);

【讨论】:

【参考方案2】:

试试这个:

CustomSpannableString 类 onClick 函数内部

@Override
public void onClick(View v)
    val textView = v as TextView
    val s = textView.text as Spanned
    val startCoordinates = s.getSpanStart(this)
    val endCoordinates = s.getSpanEnd(this)
    return  arrayOf(startCoordinates, endCoordinates)

不在 spannableString 类中

val textView = findView...   // txtView which text is set to SpannableString
val s = textView.text as Spanned 
// CustomSpannableStringObj of type CustomSpannableString 
val startCoordinates = s.getSpanStart(CustomSpannableStringObj)
val endCoordinates = s.getSpanEnd(CustomSpannableStringObj)

【讨论】:

以上是关于如何在 TextView 中获取 ClickableSpan 的坐标?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Activity 中获取 Widget 的 TextView 的文本?

如何从alertview中获取textview的值[重复]

如何在Firebase中获取用户数作为计数在android TextView中

如何在android编程中获取放置在小部件上的textview文本

如何获取 android TextView 的默认文本颜色?

iPhone:如何在不考虑宽度的情况下获取textView中输入的行数