I have set html data to my textview. When I select any word/characters from textview I want to bold that word and replace original html data with new one.
String html = "<p>hello this is android testing</p>";
Like this my html maybe have many html tags in it. If I want to make “android” word bold, how can I replace original html string with “android“.
I want <p>hello this is <strong>android</strong> testing</p>
as result.
With the following code, you can highlight formatted text more than once and each time you can get the cumulative result of all highlights.
int getOccuranceNumber(String text ,String selection, int selectionStartIndex){
int index = text.indexOf(selection);
int occuranceNumber = 0;
while (index >= 0) {
if(index == selectionStartIndex){
return occuranceNumber;
}else {
index = text.indexOf(selection, index + 1);
occuranceNumber++;
}
}
return occuranceNumber;
}
int getOccuranceIndex(String text ,String selection, int occuranceNumber){
int index = text.indexOf(selection);
int i = 0;
while (i!=occuranceNumber) {
index = text.indexOf(selection, index + 1);
i++;
}
return index;
}
public String toHex(String arg) {
TextView textV = new TextView(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textV.setText(Html.fromHtml(arg,Html.FROM_HTML_MODE_LEGACY));
}else{
textV.setText(Html.fromHtml(arg));
}
String textFormated ="";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textFormated = Html.toHtml((Spanned) textV.getText(),TO_HTML_PARAGRAPH_LINES_CONSECUTIVE).toString();
}else{
textFormated = Html.toHtml((Spanned) textV.getText()).toString();
}
return textFormated.replace("<p dir="rtl">","").replace("</p>","").replace("n","");
}
public void highLightText(TextView textView){
String textFormated ="";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textFormated = Html.toHtml((Spanned) textView.getText(),TO_HTML_PARAGRAPH_LINES_CONSECUTIVE).toString();
}else{
textFormated = Html.toHtml((Spanned) textView.getText()).toString();
}
String text = textView.getText().toString();
String selection = text.substring(textView.getSelectionStart(),textView.getSelectionEnd());
int occuranceNum = getOccuranceNumber(text,selection,textView.getSelectionStart());
String selectionHex = toHex(selection);
int formatedTextSelectionStart = getOccuranceIndex(textFormated,selectionHex,occuranceNum);
if(formatedTextSelectionStart<0)return;
int formatedTextSelectionEnd = formatedTextSelectionStart + selectionHex.length();
String formatedTextPart1 = textFormated.substring(0,formatedTextSelectionStart);
String formatedTextPart2 = textFormated.substring(formatedTextSelectionStart,formatedTextSelectionEnd);
String formatedTextPart3 = textFormated.substring(formatedTextSelectionEnd,textFormated.length());
String colorOpenTag="<font color="#f7c627">";
String colorCloseTag="</font>";
String finalText = formatedTextPart1+colorOpenTag+formatedTextPart2+colorCloseTag+formatedTextPart3;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textView.setText(Html.fromHtml(finalText,Html.FROM_HTML_MODE_LEGACY));
}else{
textView.setText(Html.fromHtml(finalText));
}
}
You can first set you string content into the TextView
and then use setCustomSelectionActionModeCallback(...)
to intercept the selection within the TextView.
In the example bellow a selected word will be surrounded by <strong>...</strong>
.
For example selecting “testing” will make the following string visible into the TextView.
hello this is android testing android bla bla android bla bla android bla
Then selecting the last instance on “android” in the already transformed TextView content will make the following string visible into the TextVIew.
hello this is android testing android bla bla android bla bla android bla
Code :
public class MainActivity extends AppCompatActivity {
String yourString = "<p>hello this is android testing android bla bla android bla bla android bla</p>";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView)findViewById(R.id.opening_today);
tv.setText(Html.fromHtml(yourString));
tv.setCustomSelectionActionModeCallback(new CallbackListener(tv));
}
class CallbackListener implements ActionMode.Callback{
private TextView tv;
private String strongS = "<strong>";
private String strongE = "</strong>";
public CallbackListener(TextView tv) {
this.tv = tv;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
int start = tv.getSelectionStart();
int end = tv.getSelectionEnd();
if( start == 0 && end == 0)
return false;
String content = tv.getText().toString();
String token = content.substring(start, end);
String before = content.substring(0, start);
String after = content.substring(end, content.length());
content = makeItStrong(before, after, token);
tv.setText(Html.fromHtml(content));
return false;
}
private String makeItStrong(String before, String after, String token){
return cleanTags(before, strongS, strongE) + strongS + token + strongE + cleanTags(after, strongS, strongE);
}
private String cleanTags(String source, String... exp){
for(String s: exp){
source = source.replace(s, "");
}
return source;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return true; }
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }
@Override
public void onDestroyActionMode(ActionMode mode) {}
}
}