Limitations: only one word per sentence is clickable and should be unique
To know what word should be clickable we need to create sentences structure, e.g. in json file (R.raw.sentences - sentences.json).
{
"sentences": [
{
"phrase": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"target": "consectetur",
"action": "consectetur!"
},
{
"phrase": "Maecenas dictum massa laoreet pellentesque auctor.",
"target": "auctor",
"action": "auctor!"
},
{
"phrase": "Maecenas consequat, eros at finibus semper, neque sem euismod nisi, ac vulputate justo dui vitae urna.",
"target": "vitae",
"action": "vitae!"
}
]
}
Next step is to convert json to string and parse it.
private CharSequence rawToClickableSpanString(@RawRes int rawRes) {
String str = streamToString(getResources().openRawResource(rawRes));
return stringToSpannableString(str);
}
private CharSequence stringToSpannableString(String jsonString) {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Sentences> jsonAdapter = moshi.adapter(Sentences.class);
Sentences sentences = null;
try {
sentences = jsonAdapter.fromJson(jsonString);
} catch (IOException e) {
e.printStackTrace();
}
if (sentences != null) {
for (SentencesItem sentencesItem : sentences.getSentences()) {
final String target = sentencesItem.getTarget();
final int start = sentencesItem.getPhrase().indexOf(target);
final int end = start + target.length();
SpannableString ss = new SpannableString(sentencesItem.getPhrase());
ss.setSpan(new CustomClickableSpan(sentencesItem.getAction()) {
@Override
void onClick(View view, String action) {
Toast.makeText(view.getContext(), action, Toast.LENGTH_SHORT).show();
}
}, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableStringBuilder.append(ss);
spannableStringBuilder.append("\n");
}
}
CharSequence charSequence = null;
if (spannableStringBuilder.length() > "\n".length()) {
charSequence = spannableStringBuilder.subSequence(0, spannableStringBuilder.length() - "\n".length());
}
return charSequence;
}
public String streamToString(InputStream is) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader input = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = input.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
if (sb.length() > "\n".length()) {
sb.setLength(sb.length() - "\n".length());
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
ClickableSpan should store text to be shown, so we create custom ClickableSpan.
private abstract class CustomClickableSpan extends ClickableSpan {
private String action;
public CustomClickableSpan(String action) {
this.action = action;
}
@Override
public void onClick(View widget) {
onClick(widget, action);
}
abstract void onClick(View widget, String action);
}
Finally we pass the result to textView and we set it as clickable.
TextView textView = findViewById(R.id.textView1);
textView.setText(rawToClickableSpanString(R.raw.sentences));
textView.setMovementMethod(LinkMovementMethod.getInstance());

I have used Moshi library to parse pojo json:
implementation 'com.squareup.retrofit2:converter-moshi:2.0.0'
and library for annotations:
implementation 'org.glassfish:javax.annotation:10.0-b28'
Classes for pojo from json file:
@Generated("com.robohorse.robopojogenerator")
public class Sentences{
@Json(name = "sentences")
private List<SentencesItem> sentences;
public void setSentences(List<SentencesItem> sentences){
this.sentences = sentences;
}
public List<SentencesItem> getSentences(){
return sentences;
}
@Override
public String toString(){
return
"Sentences{" +
"sentences = '" + sentences + '\'' +
"}";
}
}
@Generated("com.robohorse.robopojogenerator")
public class SentencesItem{
@Json(name = "phrase")
private String phrase;
@Json(name = "action")
private String action;
@Json(name = "target")
private String target;
public void setPhrase(String phrase){
this.phrase = phrase;
}
public String getPhrase(){
return phrase;
}
public void setAction(String action){
this.action = action;
}
public String getAction(){
return action;
}
public void setTarget(String target){
this.target = target;
}
public String getTarget(){
return target;
}
@Override
public String toString(){
return
"SentencesItem{" +
"phrase = '" + phrase + '\'' +
",action = '" + action + '\'' +
",target = '" + target + '\'' +
"}";
}
}