Monday, November 16, 2015

Text Highlighter Android Demo





Description:

If you are developing text / notepad app, you should give user to highlight words.Here is the demo app which helps you to fulfill this function.

In this app, We have use one custom class to store word's starting and ending position and word in ArrayList. It will help you to get highlighted words globally.

PS: If user select already highlighted word then you have to de-Highlight that word. We also has to remove it from ArrayList.

Here is the step by step code to do this.

First, add below code to activity_main.xml file for layout.


activity_main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fab="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="0.4"
    android:orientation="vertical"
    android:padding="5dip" >

    <EditText
        android:id="@+id/note"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:autoText="false"
        android:background="@android:color/white"
        android:capitalize="none"
        android:ems="10"
        android:fadingEdge="none"
        android:gravity="top"
        android:padding="5dp"
        android:hint="Enter text here..."
        android:scrollbars="vertical|horizontal"
        android:textColor="@android:color/black"
        android:textSize="22dp" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/btnGetHighlightedWords"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Get Highlighted Words" />
    
</LinearLayout>

Create custom class named SelectedWordPOJO and add below code into it.

SelectedWordPOJO.java

public class SelectedWordPOJO {

String word;
int start;
int end;

public SelectedWordPOJO(String word, int start, int end){
this.word = word;
this.start = start;
this.end = end;
}

public String getWord() {
return word;
}

public void setWord(String word) {
this.word = word;
}

public int getStart() {
return start;
}

public void setStart(int start) {
this.start = start;
}

public int getEnd() {
return end;
}

public void setEnd(int end) {
this.end = end;
}

}

Now Go to MainActivity.java class and ad below code:

MainActivity.java


import java.util.ArrayList;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

EditText etText;
ArrayList<SelectedWordPOJO> selectedWordsCounter = new ArrayList<SelectedWordPOJO>();
Button btnGetHighlightedWords;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

etText = (EditText) findViewById(R.id.note);
etText.setCustomSelectionActionModeCallback(new StyleCallBack());
etText.setVerticalScrollBarEnabled(true);
etText.requestFocus();

btnGetHighlightedWords = (Button) findViewById(R.id.btnGetHighlightedWords);

btnGetHighlightedWords.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
StringBuffer sb = new StringBuffer();
for(int i = 0 ; i< selectedWordsCounter.size() ; i++){
sb.append(selectedWordsCounter.get(i).word+",\n");
}
etText.setText("Highlighted Words:\n\n"+sb.toString());
}
});

}

class StyleCallBack implements ActionMode.Callback {

public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.style, menu);
menu.removeItem(android.R.id.selectAll);
menu.removeItem(android.R.id.copy);
menu.removeItem(android.R.id.cut);
return true;
}

public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}

public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
int start = etText.getSelectionStart();
int end = etText.getSelectionEnd();

SpannableStringBuilder ssb = new SpannableStringBuilder(etText.getText());
final ForegroundColorSpan foreGroundWhite = new ForegroundColorSpan(Color.WHITE); 
final BackgroundColorSpan backgroundRed = new BackgroundColorSpan(Color.RED);
// final CharacterStyle csBold = new StyleSpan(Typeface.BOLD);

final ForegroundColorSpan foreGroundBlack = new ForegroundColorSpan(Color.BLACK); 
final BackgroundColorSpan backgroundWhite = new BackgroundColorSpan(Color.WHITE);
// final CharacterStyle csNormal = new StyleSpan(Typeface.NORMAL);

switch (item.getItemId()) {
case R.id.more:

final CharSequence selectedText = etText.getText().subSequence(start, end);
boolean b = checkWordStorage(selectedText.toString(), start, end);
if(b){
// DESELECT
       ssb.setSpan(backgroundWhite, start, end, 1);
//    ssb.setSpan(csNormal, start, end, 1);
           ssb.setSpan(foreGroundBlack, start, end, 1);
           Log.v("Start:"+start,"End:"+end);
           etText.setText(ssb);

}else{
//SELECT
   ssb.setSpan(backgroundRed, start, end, 1);
 //  ssb.setSpan(csBold, start, end, 1);
           ssb.setSpan(foreGroundWhite, start, end, 1);
           Log.v("Start:"+start,"End:"+end);
           etText.setText(ssb);
}
           return true;
}
return false;
}

public void onDestroyActionMode(ActionMode mode) {
}
}

private boolean checkWordStorage(String word, int st, int end){
boolean result = false;
for(int i = 0 ; i < selectedWordsCounter.size() ; i++){
int eachStart = selectedWordsCounter.get(i).getStart();
int eachEnd = selectedWordsCounter.get(i).getEnd();
String eachWord = selectedWordsCounter.get(i).getWord();
 
if(word.equals(eachWord) && st == eachStart && end == eachEnd){
// word is already exist and need to DESELECT
selectedWordsCounter.remove(i);
result = true;
break;
}
}
 
if(!result){
// word is not found in array, We need to add it in array  
selectedWordsCounter.add(new SelectedWordPOJO(word, st, end));
}
 
return result;
}
 
}

In Above code, We uses StyleCallBack method which handles styleActionBar. Comment below code, If you want to give feature of cut,copy,paste text.

menu.removeItem(android.R.id.selectAll);
menu.removeItem(android.R.id.copy);
menu.removeItem(android.R.id.cut);

This StyleCallBack method will identify whether selected word is already exist in ArrayList or not. If it is already available then it will remove it from arraylist and also remove red highlight color. If it is not exist then it will add it in arraylist and highlight word with Red color.

Last, You have to create one menu file in /res/menu/ directory named style.xml and add below code into it.

style.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/more"
        android:enabled="true"
        android:icon="@android:drawable/ic_menu_crop"
        android:showAsAction="always"
        android:title="More"
        android:visible="true"/>
    
</menu>

PS: Don't forget to set minSDKVersion to 11 as StyleCallBack method supports min 11 or greater.


Download Full Source Code: GitHub



5 comments: