This post is about how to change paragraph color which is current speaking 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 an event that will highlight the paragraph 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="250dp" 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="speakClicked" 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.androidhightlighttextdemo; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.speech.tts.UtteranceProgressListener; 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 java.util.ArrayList; import java.util.Arrays; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener { private int paragraphCount = 0; private ArrayList<String> stringArrayList = new ArrayList<>(); TextView textView; TextToSpeech tts; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.tv_text); //creating TTS instance tts = new TextToSpeech(this, this); textView.setText(getString(R.string.text)); } private void speakText() { if (paragraphCount == 0) { stringArrayList = new ArrayList<>(Arrays.asList(textView.getText().toString().split("\n"))); } try { SpannableString spannableString = new SpannableString(textView.getText().toString()); spannableString.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorPrimaryDark)), 0, textView.getText().toString().length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); spannableString.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorAccent)), textView.getText().toString().indexOf(stringArrayList.get(paragraphCount)), textView.getText().toString().indexOf(stringArrayList.get(paragraphCount)) + stringArrayList.get(paragraphCount).length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); tts.speak(stringArrayList.get(paragraphCount), TextToSpeech.QUEUE_FLUSH, null, "UniqueID"); textView.setText(spannableString); } catch (Exception e) { e.printStackTrace(); } } //Called to signal the completion of the TextToSpeech engine initialization. @Override public void onInit(int i) { //Listener for events relating to the progress of an utterance tts.setOnUtteranceProgressListener(new UtteranceProgressListener() { //called when speaking starts @Override public void onStart(String utteranceId) { Log.i("TTS", "utterance started"); } //called when speaking is finished. @Override public void onDone(String utteranceId) { if (stringArrayList.size() - 1 != paragraphCount) { paragraphCount++; speakText(); } else { paragraphCount = 0; } Log.i("TTS", "utterance done"); } //called when an error has occurred during processing. @Override public void onError(String utteranceId) { Log.i("TTS", "utterance error"); } }); } public void speakClicked(View ignored) { speakText(); } }
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.
- 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.