Obtener posición absoluta para un desplazamiento dado en TextView (Android)

Tengo un TextView en el que quiero colocar un bloque de color sólido sobre determinadas palabras de TextView, por ejemplo:

"Esta es una cadena de texto, quiero poner un rectángulo sobre esta palabra" – por lo tanto, "WORD" tendría un rectángulo con un color sólido sobre ella.

Para hacer esto, estoy pensando en reemplazar el método onDraw (Canvas canvas), para dibujar un bloque sobre el texto. Mi único problema es encontrar una forma eficiente de obtener la posición absoluta de una determinada palabra o carácter.

Básicamente, estoy buscando algo que hace exactamente lo contrario del método getOffsetForPosition (float x, float y)

Basado en este post: ¿Cómo obtener coordenadas de un ClickableSpan dentro de un TextView? , He logrado utilizar este código para poner un rectángulo encima del texto:

protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.WHITE); // Initialize global value TextView parentTextView = this; Rect parentTextViewRect = new Rect(); // Find where the WORD is String targetWord = "WORD"; int startOffsetOfClickedText = this.getText().toString().indexOf(targetWord); int endOffsetOfClickedText = startOffsetOfClickedText + targetWord.length(); // Initialize values for the computing of clickedText position Layout textViewLayout = parentTextView.getLayout(); 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, parentTextViewRect); // Update the rectangle position to his real position on screen int[] parentTextViewLocation = {0,0}; parentTextView.getLocationOnScreen(parentTextViewLocation); double parentTextViewTopAndBottomOffset = ( //parentTextViewLocation[1] - parentTextView.getScrollY() + parentTextView.getCompoundPaddingTop() ); parentTextViewRect.top += parentTextViewTopAndBottomOffset; parentTextViewRect.bottom += parentTextViewTopAndBottomOffset; // In the case of multi line text, we have to choose what rectangle take if (keywordIsInMultiLine){ WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); int screenHeight = display.getHeight(); int dyTop = parentTextViewRect.top; int dyBottom = screenHeight - parentTextViewRect.bottom; boolean onTop = dyTop > dyBottom; if (onTop){ endXCoordinatesOfClickedText = textViewLayout.getLineRight(currentLineStartOffset); } else{ parentTextViewRect = new Rect(); textViewLayout.getLineBounds(currentLineEndOffset, parentTextViewRect); parentTextViewRect.top += parentTextViewTopAndBottomOffset; parentTextViewRect.bottom += parentTextViewTopAndBottomOffset; startXCoordinatesOfClickedText = textViewLayout.getLineLeft(currentLineEndOffset); } } parentTextViewRect.left += ( parentTextViewLocation[0] + startXCoordinatesOfClickedText + parentTextView.getCompoundPaddingLeft() - parentTextView.getScrollX() ); parentTextViewRect.right = (int) ( parentTextViewRect.left + endXCoordinatesOfClickedText - startXCoordinatesOfClickedText ); canvas.drawRect(parentTextViewRect, paint); } 

Puedes usar espacios para eso. Primero crear un spannable para su texto, como este:

 Spannable span = new SpannableString(text); 

A continuación, poner un espacio alrededor de la palabra que desea resaltar, algo así:

 span.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 

Desafortunadamente no sé de una extensión existente que ponga una frontera alrededor de una palabra. He encontrado UnderlineSpan, y también BackgroundColorSpan , tal vez estos también son útiles para usted, o puede echar un vistazo al código y ver si puede crear un BorderSpan basado en uno de ellos.

En vez de dibujar un rectángulo sobre la PALABRA, usted podría substituir simplemente sus caracteres por un símbolo unicode apropiado como U + 25AE (▮ rectángulo vertical negro).

Así que tendrías

"Esta es una cadena de texto, quiero poner un rectángulo sobre este ▮▮▮▮"

Si eso es suficiente. Vea por ejemplo Wikipedia para una lista de wast de símbolos de unicode.

Si realmente necesita pintar ese cuadro negro puede hacer lo siguiente siempre y cuando su texto está en una sola línea:

Calcular el ancho de la parte de texto antes de 'WORD' como se explica aquí para encontrar el borde izquierdo de la caja y calcuate el ancho de 'WORD' utilizando el mismo método para encontrar el ancho de la caja.

Para un texto multilínea el método explicado también podría funcionar, pero creo que tendrás que hacer mucho trabajo aquí.

  • Separe el texto largo en las páginas de viewpager
  • Android - Cómo configurar una fuente personalizada para toda la aplicación
  • ¿Hay una manera de crear el stackoverfow "Etiquetas" EditText / Campo de entrada en Android?
  • ¿Cómo restaurar la posición de desplazamiento de texto tras la rotación de la pantalla?
  • Almacenar un texto grande y estructurado en la aplicación Android
  • Android consigue el ancho del fragmento
  • Android establece la gravedad de un TextView mediante programación
  • Android EditText texto y diseño de sugerencias
  • Desplazamiento horizontal automático en TextView
  • Mostrar el número total como texto para múltiples pines con un pin en la misma ubicación en el mapa en android
  • Acceso a TextView desde otra clase
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.