问题
I am facing issue in highlighting the text as the google reads it. Every device is having its own speed of reading the text due to which highlighting text along with sound cause problem and seems inconsistent in some devices.
I have tried Progressive Textview class to highlight the sentence as google start it reading. In this class, I need to define run task value in floats so as to start the highlighting speed. Bellow is the custom class code:
public class ProgressTextView extends AppCompatTextView {
private SpannableTask spannableTask;
private ProgressListener progressListener;
private boolean changeColor = false;
public ProgressTextView(Context context) {
super(context);
init(null);
}
public ProgressTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(getContext().obtainStyledAttributes(attrs, R.styleable.ProgressTextView));
}
public ProgressTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(getContext().obtainStyledAttributes(attrs, R.styleable.ProgressTextView, defStyleAttr, 0));
}
private void init(@Nullable TypedArray typedArray) {
this.spannableTask = new SpannableTask(this, getText().toString());
this.spannableTask.setDefaultTextColor(this.getTextColors().getDefaultColor());
int textColor = typedArray.getColor(R.styleable.ProgressTextView_highlightTextColor, 0);
if (textColor != 0) {
this.spannableTask.setHighlightTextColor(textColor);
}
}
public void addProgressListener(ProgressListener progressListener) {
this.progressListener = progressListener;
}
public SpannableTask getSpannableTask() {
return this.spannableTask;
}
public SpannableTask getSpannableTask(String text) {
this.spannableTask = new SpannableTask(this, text);
this.spannableTask.setHighlightTextColor(getResources().getColor(R.color.yellow));
this.spannableTask.setHighlightBackgroundTextColor(getResources().getColor(R.color.black));
this.spannableTask.setDefaultTextColor(getResources().getColor(R.color.text_color));
return this.spannableTask;
}
public class SpannableTask implements Runnable {
private Handler handler = new Handler();
private SpannableString spannableString;
private String text;
private ProgressTextView spannableTextView;
private int second;
private int defaultTextColor = R.color.text_color;
private int highlightTextColor = Color.YELLOW;
private int backgroundTextColor = Color.BLACK;
public SpannableTask(ProgressTextView spannableTextView, String text) {
this.text = text;
this.spannableString = new SpannableString(text);
this.spannableTextView = spannableTextView;
initTextView(defaultTextColor,backgroundTextColor, text.length());
}
public void runTask(float second) {
this.second = ((int) (second * 1000) / text.length());
new Thread(this).run();
}
public void runTask(int second) {
this.second = second / text.length();
new Thread(this).run();
}
@Override
public void run() {
for (int i = 0; i <= text.length(); i++) {
final int value = i;
handler.postDelayed(new Runnable() {
@Override
public void run() {
changeColor = true;
initTextView(highlightTextColor,backgroundTextColor, value);
if (value == text.length() && progressListener != null) {
cancel();
progressListener.complete();
}
}
}, second * i);
}
}
private void initTextView(int color,int backgroundcolor, int length) {
if(!changeColor){
this.spannableString.setSpan(new BackgroundColorSpan(Color.WHITE), 0, length, 0);
this.spannableString.setSpan( new ForegroundColorSpan(getResources().getColor(R.color.text_color)), 0,length, 0);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
spannableStringBuilder.append(spannableString);
this.spannableTextView.setText(spannableString);
}else{
this.spannableString.setSpan(new BackgroundColorSpan(color), 0, length, 0);
this.spannableString.setSpan( new ForegroundColorSpan(backgroundcolor), 0,length, 0);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
spannableStringBuilder.append(spannableString);
this.spannableTextView.setText(spannableString);
}
}
public void cancel() {
changeColor =false;
initTextView(defaultTextColor,backgroundTextColor, text.length());
handler.removeCallbacksAndMessages(null);
}
public void setDefaultTextColor(int defaultTextColor) {
this.defaultTextColor = defaultTextColor;
initTextView(defaultTextColor,backgroundTextColor, text.length());
}
public void setHighlightTextColor(int highlightTextColor) {
this.highlightTextColor = highlightTextColor;
}
public void setHighlightBackgroundTextColor(int backgroundTextColor) {
this.backgroundTextColor = backgroundTextColor;
}
}
}
And in my main voice Activity, I am using GTS to read the dynamic text
private ProgressTextView.SpannableTask target = null;
private boolean isSpeech=false;
TextToSpeech textToSpeech;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_voice);
new RetrieveFeedTask().execute("");
}
public static class RetrieveFeedTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
try {
String apiUrl= "https://maps.googleapis.com/maps/api/geocode/json?latlng="+mCurrentLocation.getLatitude()+","+mCurrentLocation.getLongitude()+"&key=YOUR KEY";
URL url = new URL(apiUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
return null;
}
}
protected void onPreExecute() {
}
protected void onPostExecute(String response) {
if(response != null) {
try {
AddressList addressList=new Gson().fromJson(response,AddressList.class);
List<Results> mList= addressList.getResults();
List<AddressComponent> mAddressList= mList.get(0).getAddressComponents();
StringBuilder sb = new StringBuilder();
for (AddressComponent addressComponent:mAddressList) {
if(addressComponent.getTypes().contains("street_number")){
sb.append(addressComponent.getShortName()).append(" ");
}
else if(addressComponent.getTypes().contains("route")){
sb.append(addressComponent.getShortName()).append(", ");
}
else if(addressComponent.getTypes().contains("locality")){
sb.append(addressComponent.getShortName()).append(", ");
}
else if(addressComponent.getTypes().contains("administrative_area_level_1")){
sb.append(addressComponent.getLongName());
}
}
mTxtAddress.setText(sb.toString());
textSpeech();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private void textSpeech(){
textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.ENGLISH);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
Toast.makeText(getApplicationContext(), "This language is not supported!",
Toast.LENGTH_SHORT);
} else {
textToSpeech.setOnUtteranceCompletedListener(VoiceActivity.this);
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onStart(String s) {
final String keyword = s;
runOnUiThread(new Runnable() {
@Override
public void run() {
if(mTxtAddress.getText().toString().equalsIgnoreCase(keyword)){
target = mTxtAddress.getSpannableTask(mTxtAddress.getText().toString());
target.runTask(3.5f);
}
}
});
}
@Override
public void onDone(final String keyword) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(mTxtAddress.getText().toString().equalsIgnoreCase(keyword)){
target.cancel();
}
}
});
}
@Override
public void onError(String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "Error ", Toast.LENGTH_SHORT).show();
}
});
}
});
speak();
}
}
}
});
}
private void speak() {
mPlayer.stop();
isSpeech=true;
String text = mTxtEmer.getText().toString();
HashMap<String, String> params = new HashMap<String, String>();
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,text);
textToSpeech.speak(text, TextToSpeech.QUEUE_ADD, params);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, mTxtAddress.getText().toString());
textToSpeech.speak(mTxtAddress.getText().toString(), TextToSpeech.QUEUE_ADD, params);
} else {
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, mTxtAddress.getText().toString());
textToSpeech.speak(mTxtAddress.getText().toString(), TextToSpeech.QUEUE_ADD, params);
}
}
来源:https://stackoverflow.com/questions/58114281/highlighting-the-text-as-it-reads-using-google-text-to-speech