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.
Thanks! for the article. Can you please add some more feature to this app like auto scroll to the high-lighted text for long post and previous-next button to jump paragraph.