HighlightTextView un componente para Android que facilita el resaltar y añadir eventos a palabras en un TextView

Chema Pramos
3 min readOct 15, 2018

Es casi todos los proyectos nos ha tocado lidiar con un resaltado de cadenas o palabras dentro del contenido de un TextView: links, palabras en negrita, etc. También, es muy común que, además del resaltado, se añada un evento como abrir un navegador web (en el caso de los enlaces).

El sdk de Android ofrece la opción de SpannableString para poder establecer estilos a cadenas dentro de un TextView.

[SpannableString] Ejemplo de StackOverflow

final SpannableString text = 
new SpannableString("Hello stackOverflow");
text.setSpan(new RelativeSizeSpan(1.5f),
text.length()-"stackOverflow".length(), text.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(new ForegroundColorSpan(Color.RED),
3,
text.length() - 3,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(text);

Como se puede ver, el código necesario para poder resaltar cadenas es demasiado extenso. Esto se puede hacer de una forma sencilla usando HighlightTextView.

HighlightTextView es un componente que permite resaltar contenido dentro del texto de un TextView. Además, te permite añadir evento en cada resaltado realizado. Para ello, HighlightTextView se apoyará en SpannableString.

Características principales de HighlightTextView

  1. Resaltar una cadena.
  2. Añadir el evento onClick en la cadena elegida.
  3. Personalizar con un estilo la cadena a resaltar.
  4. Añadir múltiples estilos.
  5. Empezar a buscar la cadena en una posición determinada.
  6. Establecer el número de ocurrencias que se quieren resaltar.
  7. Ignorar mayúsculas y minúsculas.
  8. Configurarse a través de xml o por código.
  9. Trabaja con TextView personalizados.

Opciones disponibles desde XML

  • htv_highlight_text: Cadena a buscar en el texto del TextView. Valor obligatorio.
  • htv_start_position_occurrence: Posición desde donde empieza a buscar la subcadena. Por defecto, posición 0.
  • htv_limit: Número de palabras que se quieren encontrar. Por defecto, todas. Opciones disponibles: All, First, NumLimit(num), Default
  • htv_highlight_style: Establece el estilo de la cadena a buscar. Por defecto, BOLD.
  • htv_ignorecase: Establece si se quiere o no ignorar las mayúsculas de las minúsculas.

Ejemplos desde XML.

<com.jmperezra.highlighttextview.HighlightTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text_lorem_ipsum"
app:htv_highlight_text="@string/example2_text_to_highlight"
app:htv_ignorecase="false"
app:htv_limit="1"
app:htv_start_position_occurrence="0"
style="@style/Example"
app:htv_highlight_style="@style/Bold"
/>

Resultado:

Opciones disponibles desde código.

Desde programación podemos realizar dos opciones que no se pueden desde XML. Estas opciones son:

  1. Definir múltiples estilos para múltiples cadenas a resaltar.
  2. Añadir eventos a las cadenas resaltadas.

Las opciones de establecen a través de los estados de un ViewModel (POJO). Estos estados son:

  • textToHighLight: Cadena a buscar en el texto del TextView. Valor obligatorio.
  • clickHighlightText: Acción que se ejecuta tras hacer click en la cadena resaltada. Por defecto None.
  • startPositionOccurrence: Posición desde donde empieza a buscar la subcadena. Por defecto, posición 0.
  • limit: Número de palabras que se quieren encontrar. Por defecto, todas. Opciones disponibles: All, First, NumLimit(num), Default
  • styleHighlightText: Establece el estilo de la cadena a buscar. Por defecto, BOLD.
  • ignoreCase: Establece si se quiere o no ignorar las mayúsculas de las minúsculas.

El estado clickHighlightTextView usa un concepto de programación funcional Option. Con esto, se intenta evitar pasar un null.

[Kotlin] Ejemplo de código

private fun initExample10() {
htvExample10.renderHighlightViewModels(
mutableListOf(buildWithEventConfigViewModel()))
}

private fun buildWithEventConfigViewModel() = HighlightTextViewModel(
getText(R.string.example10_text_to_highlight).toString(),
R.style.Link,
Eval { showHelloWorldToast() }.some(),
0,
HighlightTextLimit.NumLimit(1),
true)

private fun showHelloWorldToast() {
Toast.makeText(this,
R.string.hello_world,
Toast.LENGTH_SHORT).show()
}

[Java] Ejemplo de código

private void initExample9() {
HighlightTextView htv = findViewById(R.id.htvExample9);
htv.renderHighlightViewModels(
Collections.singletonList(buildFullConfigViewModel()));
}

private HighlightTextViewModel buildFullConfigViewModel() {
return new HighlightTextViewModel(
getText(R.string.example9_text_to_highlight).toString(),
R.style.Link,
None.INSTANCE,
0,
new HighlightTextLimit.All(),
true);
}

Ejemplo con múltiples resaltados:

private fun initExample11() {
htvExample11.renderHighlightViewModels(
mutableListOf(buildRedViewModel(),
buildGreenViewModel(),
buildOrangeViewModel()))
}

private fun buildRedViewModel() =
HighlightTextViewModel(
getText(R.string.example11_text_to_highlight_1).toString(),
R.style.Red,
Eval { showRedToast() }.some(),
0,
HighlightTextLimit.All(),
true)

private fun buildGreenViewModel() =
HighlightTextViewModel(
getText(R.string.example11_text_to_highlight_2).toString(),
R.style.Green,
None,
0,
HighlightTextLimit.NumLimit(1),
true)

private fun buildOrangeViewModel() =
HighlightTextViewModel(
getText(R.string.example11_text_to_highlight_3).toString(),
R.style.Orange,
Eval { showOrangeToast() }.some(),
0,
HighlightTextLimit.First(),
true)

private fun showOrangeToast() {
Toast.makeText(this,
R.string.hello_orange_world,
Toast.LENGTH_SHORT).show()
}

private fun showRedToast() {
Toast.makeText(this,
R.string.hello_red_world,
Toast.LENGTH_SHORT).show()
}

Resultado:

Resultado con múltiples resaltados.

Puedes encontrar el código y toda la documentación en mi GitHub:

[GitHub — Chema Pramos] (https://github.com/jmperezra/HighlightTextView)

--

--