Android highlight a word in TextToSpeech

This post is about how to highlight the word while speech is running in TextToSpeech.

Creating new project

1. Create a new project by going to File  New Android Project, fill the required details and then click on finish.

2. The below layout file consist of two textView and a button to trigger a event that will highlight the word while speech is running in TextToSpeech.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:id="@+id/tv_text_to_speech"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_50dp"
android:gravity="center"
android:text="@string/text_to_speech"
android:textColor="@color/colorPrimaryDark"
android:textSize="@dimen/textSize_30sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginLeft="@dimen/margin_10dp"
android:layout_marginRight="@dimen/margin_10dp"
android:layout_marginTop="@dimen/margin_30dp"
android:background="@drawable/background"
android:textColor="@color/colorPrimaryDark"
android:padding="@dimen/padding_8dp"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="@dimen/textSize_25sp"
app:layout_constraintStart_toStartOf="@+id/tv_text_to_speech"
app:layout_constraintTop_toBottomOf="@+id/tv_text_to_speech" />

<Button
android:id="@+id/btn_speak_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_30dp"
android:background="@color/colorPrimary"
android:padding="@dimen/padding_12dp"
android:onClick="startClicked"
android:text="@string/speak_text"
android:textColor="@android:color/white"
android:textSize="@dimen/textSize_18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="@+id/tv_text"
app:layout_constraintStart_toStartOf="@+id/tv_text"
app:layout_constraintTop_toBottomOf="@+id/tv_text" />

</androidx.constraintlayout.widget.ConstraintLayout>

3. Open MainActivity.java, implement it from TextToSpeech.OnInitListener and add the below code.

MainActivity.java

package com.c1ctech.highlighttextdemo;

import android.graphics.Color;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
TextToSpeech tts;

String sentence = "The quick brown fox jumps over the lazy dog.";

TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

textView = findViewById(R.id.tv_text);
textView.setText(sentence);

// creating TTS instance
tts = new TextToSpeech(this, this);

}

public void onInit(int status) {

tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {

@Override
public void onStart(String utteranceId) {
Log.i("TTS", "utterance started");
}

@Override
public void onDone(String utteranceId) {
Log.i("TTS", "utterance done");
}

@Override
public void onError(String utteranceId) {
Log.i("TTS", "utterance error");
}

@Override
public void onRangeStart(String utteranceId,
final int start,
final int end,
int frame) {
Log.i("TTS", "onRangeStart() ... utteranceId: " + utteranceId + ", start: " + start
+ ", end: " + end + ", frame: " + frame);


// onRangeStart (and all UtteranceProgressListener callbacks) do not run on main thread
// ... so we explicitly manipulate views on the main thread:
runOnUiThread(new Runnable() {
@Override
public void run() {

Spannable textWithHighlights = new SpannableString(sentence);

textWithHighlights.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(textWithHighlights);

}
});
}
});

}

public void startClicked(View ignored) {

tts.speak(sentence, TextToSpeech.QUEUE_FLUSH, null, "UNIQUE_UTTERANCE_ID");

}

@Override
public void onDestroy() {
//don't forget to shutdown tts
if (tts != null) {
tts.stop();
tts.shutdown();
}
super.onDestroy();
}

}

Note: The setOnUtteranceProgressListener() method must be called before speak() is called.

In the above code,

  • onInit(): Called to signal the completion of the TextToSpeech engine initialization.
  • speak(): Speaks the text using the specified queuing strategy and speech parameters.
  • onStart(): called when speaking starts (soon after calling speak()). 
  • onDone(): called when speaking is finished.
  • onError(): called when an error has occurred during processing.
  • onRangeStart(): called when the TTS service is about to speak the specified range of the utterance with the given utteranceId.
  • stop(): stop the speak.
  • shutdown(): releases the resources used by the TextToSpeech engine.

4. Now run your project and test your app by clicking the button.

2 thoughts on “Android highlight a word in TextToSpeech”

  1. With a long text like that is not working.
    “Mr Jones had a few days’, holiday, so he said \”I’m going to go to the mountains by train.\” He put on his best clothes, took a small bag, went to the station and got into the train. He had a beautiful hat, and he often put his head out of the window during the trip and looked at the mountains. But the wind pulled his hat off.\n” +
    “\n” +
    “Mr Jones quickly took his old bag and threw that out of the window too.\n” +
    “\n” +
    “The other people in the carriage laughed. \”Is your bag going to bring your beautiful hat back?\” they asked.\n” +
    “\n” +
    “\”No,\” Mr Jones answered, \”but there’s no name and no address in my hat, and there’s a name and an address on the bag. Someone’s going to find both of them near each other, and he’s going to send me the bag and the hat.\””

    Can you fix that?

    1. Arun Chandravanshi

      This is working correctly your text formatting is not correct

      Either you define your data into the string.xml or if you are getting data at runtime then please add some logic to format the data.

      For example, I tried to format your data like this way :

      String text=”\”Mr Jones had a few days’, holiday, so he said \”I’m going to go to the mountains by train.\” He put on his best clothes, took a small bag, went to the station and got into the train. He had a beautiful hat, and he often put his head out of the window during the trip and looked at the mountains. But the wind pulled his hat off.\n” +”\n” +
      “\”\n” +”\n” +
      “\”Mr Jones quickly took his old bag and threw that out of the window too.\n” +”\n” +
      “\”\n” +”\n” +
      “\”The other people in the carriage laughed. \”Is your bag going to bring your beautiful hat back?\” they asked.\n” +”\n” +
      “\”\n” +”\n” +
      “\”No,\” Mr Jones answered, \”but there’s no name and no address in my hat, and there’s a name and an address on the bag. Someone’s going to find both of them near each other, and he’s going to send me the bag and the hat.\”\””;

Leave a Reply