part - 35 - Search ListView - Spannable Concate

 MainActivity.java : 

package first.learn.listviewsearch;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

EditText editText;
ListView listView2;

ArrayList<String> arrayList ;
SearchAdapter mSearchAdapter ;
Context mContext ;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mContext = this ;

listView2 = (ListView) findViewById(R.id.listView2);
editText = (EditText) findViewById(R.id.editText);

arrayList = new ArrayList<>();


for (int i = 0; i<101; i++){
arrayList.add("item : "+ i);

}



mSearchAdapter = new SearchAdapter(mContext, R.layout.list_item, R.id.alquran_text, arrayList);

listView2.setAdapter(mSearchAdapter);





editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

System.out.println("EditText text beforeTextChanged: "+ s);
mSearchAdapter.getFilter().filter(s);


}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mSearchAdapter.getFilter().filter(s);
System.out.println("EditText text onTextChanged: "+ s);


}

@Override
public void afterTextChanged(Editable s) {

System.out.println("EditText text afterTextChanged: "+ s);

mSearchAdapter.getFilter().filter(s);
}
});



listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

System.out.println("Show Position new: "+ position);
System.out.println("Show String new: "+ arrayList.get(position));

int originalPosition =(int) mSearchAdapter.getItemId(position);

System.out.println("Show Position Original : "+ originalPosition);
System.out.println("Show String Original : "+ arrayList.get(originalPosition));


}
});




}
}

activity_main.xml : 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
android:layout_margin="16dp">

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editText"/>



<ListView
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/listView2"/>



</LinearLayout>


SearchAdapter.java : 

package first.learn.listviewsearch;

/**
* Created by bismillah on 11/1/2017.
*/

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.Typeface;
import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.TextView;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class SearchAdapter extends ArrayAdapter<String> {
private final LayoutInflater mInflater;
private final Context mContext;
private final int mResource;
private List<String> mObjects;
private int mFieldId = 0;
private ArrayList<String> mOriginalValues;
private ArrayFilter mFilter;
private final Object mLock = new Object();
private String mSearchText; // this var for highlight




public SearchAdapter(Context context, int resource, int textViewResourceId, String[] objects) {
super(context, resource, textViewResourceId, objects);
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = resource;
mObjects = Arrays.asList(objects);
mFieldId = textViewResourceId;
}

public SearchAdapter(@NonNull Context context, int resource,int textViewResourceId, @NonNull List<String> objects) {
super(context, resource,textViewResourceId, objects);
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = resource;
mObjects = objects;
mFieldId = textViewResourceId;
}

@NonNull
@Override
public Context getContext() {

return mContext;
}

@Override
public int getCount() {
return mObjects.size();
}

@Override
public String getItem(int position) {
return mObjects.get(position);
}

@Override
public int getPosition(String item) {
return mObjects.indexOf(item);
}

String TAG = "searchOnubad";

@Override
public long getItemId(int position) {
int itemID;

if (mOriginalValues == null)
{
itemID = position;
}
else
{
itemID = mOriginalValues.indexOf(mObjects.get(position));
}
return itemID;

}

@NonNull
@Override
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}


private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();

int j =0;

if (mOriginalValues == null) {
synchronized (mLock) {
mOriginalValues = new ArrayList<>(mObjects);
}
}

if (prefix == null || prefix.length() == 0) {
mSearchText = "";
ArrayList<String> list;
synchronized (mLock) {
list = new ArrayList<>(mOriginalValues);
}
results.values = list;
results.count = list.size();
} else {
String prefixString = prefix.toString().toLowerCase();

mSearchText = prefixString;

ArrayList<String> values;

synchronized (mLock) {
values = new ArrayList<>(mOriginalValues);
}

final int count = values.size();
final ArrayList<String> newValues = new ArrayList<>();

for (int i = 0; i < count; i++) {
final String value = values.get(i);
final String valueText = value.toLowerCase();

// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString) || valueText.contains(prefixString)) {
newValues.add(value); j++;
} else {
final String[] word = valueText.split(" ");
final int wordCount = word.length;

// Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {

if (word[k].startsWith(prefixString)|| word[k].contains(prefixString)) {
newValues.add(value);

break;
}
}
}
}

results.values = newValues;
results.count = newValues.size();
}

return results;
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
//noinspection unchecked
mObjects = (List<String>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}


public static CharSequence highlight(String searchText, String originalText) {

// String normalizedText = Normalizer.normalize(originalText, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "").toLowerCase();

int start = originalText.toLowerCase().indexOf(searchText.toLowerCase());
if (start < 0) {
// not found, nothing to to

return originalText;
} else {
// highlight each appearance in the original text
// while searching in normalized text
Spannable highlighted = new SpannableString(originalText);
while (start >= 0) {
int spanStart = Math.min(start, originalText.length());
int spanEnd = Math.min(start + searchText.length(), originalText.length());


System.out.println("similarityPercent : Start : "+start+" spanStart: "+spanStart+" spanEnd: "+spanEnd+" searchText.length(): "+searchText.length()+" originalText.length(): "+originalText.length());

ColorStateList blueColor = new ColorStateList(new int[][]{new int[]{}}, new int[]{Color.BLUE});
TextAppearanceSpan highlightSpan = new TextAppearanceSpan(null, Typeface.BOLD, -1, blueColor, null);
highlighted.setSpan(highlightSpan, spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = originalText.indexOf(searchText, spanEnd);
}

return highlighted;
}
}



@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
TextView textView;

if (convertView == null) {
view = mInflater.inflate(R.layout.list_item, null);
} else {
view = convertView;
}

try {
if (mFieldId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
textView = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
textView = (TextView) view.findViewById(mFieldId);
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e);
}

// HIGHLIGHT...

String fullText = getItem(position);

if (mSearchText != null && !mSearchText.isEmpty()) {
assert fullText != null;
int startPos = fullText.toLowerCase().indexOf(mSearchText.toLowerCase());
int endPos = startPos + mSearchText.length();

if (startPos != -1) {

textView.setText(highlight(mSearchText, fullText));
} else {
textView.setText(fullText);
}
} else {
textView.setText(fullText);
}


return view;
}
}


list_item.xml : 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="6dp"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="false"
>

<!-- android:descendantFocusability="beforeDescendants"-->
<!-- android:focusableInTouchMode="false"-->

<androidx.cardview.widget.CardView
android:id="@+id/card_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"

android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp"

card_view:cardCornerRadius="5dp"
card_view:contentPadding="5dp"
card_view:contentPaddingTop="5dp"
card_view:cardElevation="10dp">

<TextView
android:id="@+id/alquran_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="@color/black"
android:layout_marginRight="2dp"
android:layout_marginLeft="2dp"
android:padding="5dp"
android:text="This is Expl "
android:lineSpacingExtra="12dp"

/>







</androidx.cardview.widget.CardView>






</LinearLayout>






No comments:

Post a Comment