searchview result in listview, but not highlight the result - android

I have created a searchview, when i type a word and press ENTER from the keyboard, the results show on a listview in 3 or 4 seconds. so i want to insert a progres spinner till the result populated. And Also I want to try to highlight the search word in the result in list view. I use "SpannableString highlightKeyword" but unable to highlight the result search word, I have tried many ways followed by several websites, but nothing happend. I Couldn't figure out where the mistake. Here are My codes:
mainactivity.java :
public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
// Declare Variables
ListView list;
ListViewAdapter adapter;
SearchView editsearch;
String[] animalNameList;
ArrayList<AnimalNames> arraylist = new ArrayList<AnimalNames>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Resources res = getResources();
String[] animalNameList = res.getStringArray(R.array.animalNameList);
// Locate the ListView in listview_main.xml
list = (ListView) findViewById(R.id.listview);
for (int i = 0; i < animalNameList.length; i++) {
AnimalNames animalNames = new AnimalNames(animalNameList[i]);
// Binds all strings into an array
arraylist.add(animalNames);
}
// Pass results to ListViewAdapter Class
adapter = new ListViewAdapter(this, arraylist);
// Binds the Adapter to the ListView
list.setAdapter(adapter);
// Locate the EditText in listview_main.xml
editsearch = (SearchView) findViewById(R.id.search);
editsearch.setOnQueryTextListener(this);
}
#Override
public boolean onQueryTextSubmit(String newText) {
String text = newText;
adapter.filter(text);
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
return false;
}
===== ListviewAdapter.java:
public class ListViewAdapter extends BaseAdapter {
// Declare Variables
Context mContext;
LayoutInflater inflater;
private List<AnimalNames> animalNamesList = null;
private ArrayList<AnimalNames> arraylist;
public ListViewAdapter(Context context, List<AnimalNames> animalNamesList) {
mContext = context;
this.animalNamesList = animalNamesList;
inflater = LayoutInflater.from(mContext);
this.arraylist = new ArrayList<AnimalNames>();
this.arraylist.addAll(animalNamesList);
}
public class ViewHolder {
TextView name;
}
#Override
public int getCount() {
return animalNamesList.size();
}
#Override
public AnimalNames getItem(int position) {
return animalNamesList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.listview_item, null);
// Locate the TextViews in listview_item.xml
holder.name = (TextView) view.findViewById(R.id.name);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
// Set the results into TextViews
holder.name.setText(animalNamesList.get(position).getAnimalName());
return view;
}
// Filter Class
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
animalNamesList.clear();
if (charText.length() == 0) {
animalNamesList.addAll(arraylist);
} else {
for (AnimalNames wp : arraylist) {
if (wp.getAnimalName().toLowerCase(Locale.getDefault()).contains(charText)) {
animalNamesList.add(wp);
}
}
}
notifyDataSetChanged();
}
////Here My problem starts :
public static SpannableString highlightKeyword(CharSequence text, Pattern p, int fgcolor, int bgcolor) {
SpannableString ss = new SpannableString(text);
ColorStateList blueColor = new ColorStateList(new int[][]{new int[]{}}, new int[]{Color.BLUE});
int start = 0;
int end;
Matcher m = p.matcher(text);
while (m.find(start)) {
start = m.start();
end = m.end();
BackgroundColorSpan bgspan = new BackgroundColorSpan(bgcolor);
ss.setSpan(bgspan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ForegroundColorSpan fgspan = new ForegroundColorSpan(fgcolor);
ss.setSpan(fgspan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = end;
}
return ss;
}
////But even did not the result word highlighted.
Thanks in Advance.

Alhamdulillah, At last I found my answer on google. Highligh in custom adapter within getview() method. As follows :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
TextView text;
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
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = (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()) {
int startPos = fullText.toLowerCase(Locale.US).indexOf(mSearchText.toLowerCase(Locale.US));
int endPos = startPos + mSearchText.length();
if (startPos != -1) {
Spannable spannable = new SpannableString(fullText);
ColorStateList blueColor = new ColorStateList(new int[][]{new int[]{}}, new int[]{Color.BLUE});
TextAppearanceSpan highlightSpan = new TextAppearanceSpan(null, Typeface.BOLD, -1, blueColor, null);
spannable.setSpan(highlightSpan, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setText(spannable);
} else {
text.setText(fullText);
}
} else {
text.setText(fullText);
}
return view;
}

Related

How to update the ListView after adding new items?

I am working on a grocery list app and having trouble refreshing the list view after adding a new item. After I add a new item in the database the ListView is not refreshed. If I go in the item details page and then come back to main activity the onCreate is called again and it refreshes it correctly.
If I call the refresh method in the addItemToDb() (on button clicked) method it duplicates my items but does not add them to the database.
Has anyone had this problem before???
Here is the code:
The list view adapter
public class ItemListViewAdapter extends ArrayAdapter<ItemModel> {
Activity activity;
int layoutResource;
ArrayList<ItemModel> itemModelArrayList = new ArrayList<>();
public ItemListViewAdapter(Activity act, int resource, ArrayList<ItemModel> data) {
super(act, resource, data);
activity = act;
layoutResource = resource;
itemModelArrayList = data;
notifyDataSetChanged();
}
#Override
public int getCount() {
return itemModelArrayList.size();
}
#Override
public ItemModel getItem(int position) {
return itemModelArrayList.get(position);
}
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
final ViewHolder holder;
if (row == null || (row.getTag()) == null) {
LayoutInflater inflater = LayoutInflater.from(activity);
row = inflater.inflate(layoutResource, null);
holder = new ViewHolder();
holder.hItemName = (TextView) row.findViewById(R.id.custom_row_productName);
holder.hItemPrice = (TextView) row.findViewById(R.id.custom_row_productPrice);
holder.hItemType = (TextView) row.findViewById(R.id.custom_row_productType);
holder.hCheckBox = (CheckBox) row.findViewById(R.id.custom_row_checkBox);
holder.hItemEdit = (ImageView) row.findViewById(R.id.custom_row_edit);
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
holder.hModel = getItem(position);
holder.hItemName.setText(holder.hModel.getItemName());
holder.hItemPrice.setText(String.valueOf(holder.hModel.getItemPrice()));
holder.hItemType.setText(holder.hModel.getItemType());
holder.hItemEdit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int itemID = holder.hModel.getItemId();
String itemName = holder.hModel.getItemName();
String itemPrice = String.valueOf(holder.hModel.getItemPrice());
String itemType = holder.hModel.getItemType();
String itemDate = holder.hModel.getItemDate();
Intent intent = new Intent(activity, ItemDetail.class);
intent.putExtra("id", itemID);
intent.putExtra("product", itemName);
intent.putExtra("price", itemPrice);
intent.putExtra("type", itemType);
intent.putExtra("date", itemDate);
startActivity(activity, intent, null);
}
});
return row;
}
public class ViewHolder {
ItemModel hModel;
TextView hItemName;
TextView hItemPrice;
TextView hItemType;
TextView hItemDate;
CheckBox hCheckBox;
ImageView hItemEdit;
}
}
And main activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHandler = new DatabaseHandler(getApplicationContext());
itemNameText = (EditText) findViewById(R.id.activity_main_productName);
itemPriceText = (EditText) findViewById(R.id.activity_main_productPrice);
itemTypeSpinner = (Spinner) findViewById(R.id.activity_main_spinner);
addButton = (Button) findViewById(R.id.activity_main_addButton);
saveListButton = (FloatingActionButton) findViewById(R.id.activity_main_fab);
ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter.createFromResource(getApplicationContext(), R.array.productTypes, R.layout.spinner_item);
itemTypeSpinner.setAdapter(spinnerAdapter);
//USE BUTTONS
addButton.setOnClickListener(this);
saveListButton.setOnClickListener(this);
//LIST_VIEW
listView = (ListView) findViewById(R.id.activity_main_listView);
//calling methods
refreshData();
}
public void refreshData() {
modelArrayListContainer.clear();
//GET ITEMS FROM DB
ArrayList<ItemModel> modelArrayListFromDB = dbHandler.getAllItems();
for (int i = 0; i < modelArrayListFromDB.size(); i++) {
int ditemID = modelArrayListFromDB.get(i).getItemId();
String dItemName = modelArrayListFromDB.get(i).getItemName();
double dItemPrice = modelArrayListFromDB.get(i).getItemPrice();
String dItemType = modelArrayListFromDB.get(i).getItemType();
String dItemDate = modelArrayListFromDB.get(i).getItemDate();
ItemModel newModel = new ItemModel();
newModel.setItemId(ditemID);
newModel.setItemName(dItemName);
newModel.setItemPrice((int) dItemPrice);
newModel.setItemType(dItemType);
newModel.setItemDate(dItemDate);
modelArrayListContainer.add(newModel);
}
//setup Adapter
itemListViewAdapter = new ItemListViewAdapter(MainActivity.this, R.layout.custom_product_layout_activity_main, modelArrayListContainer);
listView.setAdapter(itemListViewAdapter);
itemListViewAdapter.notifyDataSetChanged();
}
public void addItemToDb() {
ItemModel model = new ItemModel();
String spinnerValue = itemTypeSpinner.getSelectedItem().toString();
model.setItemName(itemNameText.getText().toString().trim()); model.setItemPrice(Double.parseDouble((itemPriceText.getText().toString().trim())));
model.setItemType(spinnerValue);
dbHandler.addItem(model);
dbHandler.close();
Log.v(TAG, "::addItemToDb - itemAdded");
}
}
You need to call refreshData() in your addItemToDb function like:
public void addItemToDb() {
ItemModel model = new ItemModel();
String spinnerValue = itemTypeSpinner.getSelectedItem().toString();
model.setItemName(itemNameText.getText().toString().trim()); model.setItemPrice(Double.parseDouble((itemPriceText.getText().toString().trim())));
model.setItemType(spinnerValue);
dbHandler.addItem(model);
dbHandler.close();
Log.v(TAG, "::addItemToDb - itemAdded");
refreshData();
}
But if you need to update data automatically from database, you need to use CursorAdaptor and use Content Providers
UPDATE
Also change your getAllItems() function in dbhandler and include the following statement in the first line of the function:
modelArrayList.clear();

Highlight searched text in custom adapter listview

I have a listview and want to search text from it. I have done it successfully but now I want to search the item and highlight the searched text in the listview. This is my filter function in the ListViewAdapter:
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
worldpopulationlist.clear();
if (charText.length() == 0) {
worldpopulationlist.addAll(arraylist);
}
else
{
for (WorldPopulation wp : arraylist)
{
// Find charText in wp
int startPos = wp.getCountry().toLowerCase(
Locale.getDefault()).indexOf(charText.toLowerCase(Locale.getDefault()));
int endPos = startPos + charText.length();
if (startPos != -1)
{
Spannable spannable = new SpannableString(wp.getCountry());
ColorStateList blueColor = new ColorStateList(new int[][] { new int[] {}}, new int[] { Color.BLUE });
TextAppearanceSpan highlightSpan = new TextAppearanceSpan(null, Typeface.BOLD, -1, blueColor, null);
spannable.setSpan(highlightSpan, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// countryTextView.setText(spannable);
worldpopulationlist.add(wp);
}
}
}
notifyDataSetChanged();
}
I have googled it and I know that Spannable is used for this purpose but its not working. Please help me and tell me if you need any other related code.
EDIT:
The tutorial I followed was from here. I used the same code with a few minor changes. I just want to highlight the searched text in the list view (just one item e.g. country in this case).
Well, I downloaded the sample project and finally came with the following. Adapt the code to your needs.
In your filter method, store the string used to perform the filter:
// Filter Class
public void filter(String searchString) {
this.searchString = searchString;
...
// Filtering stuff as normal.
}
You must declare a member string to store it:
public class ListViewAdapter extends BaseAdapter {
...
String searchString = "";
...
And, in getView you highlight the search term:
public View getView(final int position, View view, ViewGroup parent) {
...
// Set the results into TextViews
WorldPopulation item = worldpopulationlist.get(position);
holder.rank.setText(item.getRank());
holder.country.setText(item.getCountry());
holder.population.setText(item.getPopulation());
// Find charText in wp
String country = item.getCountry().toLowerCase(Locale.getDefault());
if (country.contains(searchString)) {
Log.e("test", country + " contains: " + searchString);
int startPos = country.indexOf(searchString);
int endPos = startPos + searchString.length();
Spannable spanText = Spannable.Factory.getInstance().newSpannable(holder.country.getText()); // <- EDITED: Use the original string, as `country` has been converted to lowercase.
spanText.setSpan(new ForegroundColorSpan(Color.RED), startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.country.setText(spanText, TextView.BufferType.SPANNABLE);
}
...
}
Hope it helps.
You can do like this..
public class ListViewAdapter extends BaseAdapter {
// Declare Variables
Context mContext;
LayoutInflater inflater;
String searchstring="";
private List<WorldPopulation> worldpopulationlist = null;
private ArrayList<WorldPopulation> arraylist;
public ListViewAdapter(Context context, List<WorldPopulation> worldpopulationlist) {
mContext = context;
this.worldpopulationlist = worldpopulationlist;
inflater = LayoutInflater.from(mContext);
this.arraylist = new ArrayList<WorldPopulation>();
this.arraylist.addAll(worldpopulationlist);
}
public class ViewHolder {
TextView rank;
}
#Override
public int getCount() {
return worldpopulationlist.size();
}
#Override
public WorldPopulation getItem(int position) {
return worldpopulationlist.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.listview_item, null);
// Locate the TextViews in listview_item.xml
holder.rank = (TextView) view.findViewById(R.id.ranklabel);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
// Set the results into TextViews
String faqsearchstr=worldpopulationlist.get(position).getRank().toLowerCase(Locale.getDefault());
if (faqsearchstr.contains(searchstring)) {
Log.e("test", faqsearchstr + " contains: " + searchstring);
System.out.println("if search text"+faqsearchstr);
int startPos = faqsearchstr.indexOf(searchstring);
int endPos = startPos + searchstring.length();
Spannable spanText = Spannable.Factory.getInstance().newSpannable(worldpopulationlist.get(position).getRank()); // <- EDITED: Use the original string, as `country` has been converted to lowercase.
spanText.setSpan(new ForegroundColorSpan(Color.GREEN), startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.rank.setText(spanText, TextView.BufferType.SPANNABLE);
}
else
{
System.out.println("else search text"+faqsearchstr);
holder.rank.setText(worldpopulationlist.get(position).getRank());
}
// Listen for ListView Item Click
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// Send single item click data to SingleItemView Class
Intent intent = new Intent(mContext, QuestionActivity.class);
// Pass all data rank
// intent.putExtra("rank",(worldpopulationlist.get(position).getRank()));
intent.putExtra("QuestionsIntent",((worldpopulationlist.get(position).getFaqpopulatedData())));
System.out.println("questionsss.."+(worldpopulationlist.get(position).getFaqpopulatedData()));
// Start SingleItemView Class
mContext.startActivity(intent);
}
});
return view;
}
// Filter Class
public void filter(String charText) {
this.searchstring=charText;
charText = charText.toLowerCase(Locale.getDefault());
worldpopulationlist.clear();
if (charText.length() == 0) {
System.out.println("inside filter if");
worldpopulationlist.addAll(arraylist);
}
else
{
for (WorldPopulation wp : arraylist)
{
if (wp.getRank().toLowerCase(Locale.getDefault()).contains(charText))
{
System.out.println("inside filter else");
worldpopulationlist.add(wp);
}
}
}
notifyDataSetChanged();
}
}
Use following code to highlight searched text from search/edit text
input is filtered name and mTextview is your text view which you want to highlight use this method after setting value to text view.
private void highlightString(String input, TextView mTextView) {
SpannableString spannableString = new SpannableString(mTextView.getText());
ForegroundColorSpan[] backgroundSpans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);
for (ForegroundColorSpan span : backgroundSpans) {
spannableString.removeSpan(span);
}
int indexOfKeyword = spannableString.toString().indexOf(input);
while (indexOfKeyword > 0) {
spannableString.setSpan(new ForegroundColorSpan(Color.GREEN), indexOfKeyword, indexOfKeyword + input.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
indexOfKeyword = spannableString.toString().indexOf(input, indexOfKeyword + input.length());
}
mTextView.setText(spannableString);
}

android listview with custom adapter multiselection issue

I want to make a listview item selected and the text "select" to be made to "selected", but when i click an item mutiple items get selected if I select an item at position 0 , items get selected at at a pattern, that is 0,7,14,21 and if i change the view to landscape: it will be 0 ,5,10,15, etc.
my main activity is:
public class two extends Activity implements OnQueryTextListener,OnItemClickListener {
GroupAdapter grpAdapter;
public static ArrayList<GroupsModel> arrayOfList;
public static ListView listView;
public static String base_url = "myurl";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.two);
arrayOfList = new ArrayList<GroupsModel>();
listView = (ListView) findViewById(R.id.group_listview);
listView.setOnItemClickListener(this);
listView.setTextFilterEnabled(true);
new ProgressTask(two.this).execute();
}
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
#SuppressWarnings("unused")
private two activity;
public ProgressTask(two two) {
this.activity = two;
context = two;
dialog = new ProgressDialog(context);
}
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
grpAdapter = new GroupAdapter(two.this, R.layout.two_row,arrayOfList);
listView.setAdapter(grpAdapter);
}
protected Boolean doInBackground(final String... args) {
//arrayOfList = new ArrayList<GroupsModel>();
List<NameValuePair> params = new ArrayList<NameValuePair>();
//params.add(new BasicNameValuePair("",""));
JSONParser jp = new JSONParser();
JSONArray groups_obj = jp.makeHttpRequest(base_url + "groups/all", "GET", params);
for (int i = 0; i < groups_obj.length(); i++) {
GroupsModel group = new GroupsModel();
try {
JSONObject grp = groups_obj.getJSONObject(i);
group.setGroupId(grp.getInt("id"));
group.setGroupname(grp.getString("name"));
arrayOfList.add(group);
}
catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
SearchManager searchManager = (SearchManager) getSystemService( Context.SEARCH_SERVICE );
SearchView searchView = (SearchView) menu.findItem(R.id.menu_item_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setSubmitButtonEnabled(false);
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onQueryTextChange(String newText)
{
// this is your adapter that will be filtered
if (TextUtils.isEmpty(newText))
{
listView.clearTextFilter();
}
grpAdapter.getFilter().filter(newText.toString());
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
// TODO Auto-generated method stub
view.setBackgroundColor(Color.CYAN);
}}
My adapter is:
public class GroupAdapter extends ArrayAdapter<GroupsModel> implements Filterable{
private Context activity;
private ArrayList<GroupsModel> items ;
private List<GroupsModel> arrayList;
private ArrayFilter mFilter;
private int resource;
public GroupAdapter(Activity act, int resource, ArrayList<GroupsModel> arrayList) {
super(act, resource, arrayList);
this.activity = act;
this.resource = resource;
this.items = new ArrayList<GroupsModel>();
this.items.addAll(arrayList);
this.arrayList = new ArrayList<GroupsModel>();
this.arrayList.addAll(arrayList);
}
public View getView(final int position, View convertView,final ViewGroup parent) {
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
try{
GroupsModel groups = items.get(position);
holder.group_name.setText(groups.getGroupName());
}catch(Exception e){
e.printStackTrace();
}
holder.select.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
holder.select.setText("my new text");
}
});
return convertView;
}
public class ViewHolder {
public TextView group_name,select;
}
#Override
public int getCount() {
// Total count includes list items and ads.
return items.size();
}
#Override
public GroupsModel getItem(int position)
{
// TODO Auto-generated method stub
return items.get(position);
}
#Override
public long getItemId(int position)
{
// TODO Auto-generated method stub
return position;
}
#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();
if (arrayList == null) {
synchronized (this) {
arrayList = new ArrayList<GroupsModel>(items);
}
}
if (prefix == null || prefix.length() == 0) {
ArrayList<GroupsModel> list;
synchronized (this) {
list = new ArrayList<GroupsModel>(arrayList);
}
results.values = list;
results.count = list.size();
} else {
String prefixString = prefix.toString().toLowerCase();
ArrayList<GroupsModel> values;
synchronized (this) {
values = new ArrayList<GroupsModel>(arrayList);
}
final int count = values.size();
final ArrayList<GroupsModel> newValues = new ArrayList<GroupsModel>();
for (int i = 0; i < count; i++) {
final String value = values.get(i).getGroupName();
final String valueText = value.toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(values.get(i));
} else {
final String[] words = valueText.split(" ");
final int wordCount = words.length;
// Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(values.get(i));
break;
}
}
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
items = (ArrayList<GroupsModel>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}}
I cant figure this out. Please help
You need to maintain the selected item in adapter and use it to change the text :
Adapter Code
private int selectedIndex;
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final ViewHolder holder;
LayoutInflater inflater = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(resource,parent, false);
holder = new ViewHolder();
holder.group_name = (TextView) convertView.findViewById(R.id.group_name);
holder.select = (TextView) convertView.findViewById(R.id.select);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(selectedIndex!= -1 && position == selectedIndex)
{
convert_view.setBackgroundColor(Color.CYAN);
holder.select.setText("selected");
}
else
{
convert_vie.wsetBackgroundColor(default_color);
holder.select.setText("Select");
}
//Your other code .....
return convertView ;
}
public void setSelectedIndex(position)
{
selectedIndex = position;
}
Now set the selectedIndex variable when a list item clicked.
public class MainActivity extends Activity implements OnItemClickListener
{
// Implemented onItemClickListener
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
adapter.setSelectedIndex(position);
}
}
You can add a member "checked" in GroupsModel, and initial it assign false;
In activity
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
final boolean isChecked = listView.getItem(position).isChecked();
listView.get(position).setChecked(!isChecked);
}
In getView() in adapter:
public View getView(...) {
...
if(getItem(position).isChecked()) {
// You must set root view in holder
holder.getBackground().setBackgroundColor(Color.CYAN);
}
...
}
Your problem is that Android is reusing your views, so when you scroll, the first view disappears and appears at the bottom with the same state.
What you need to do is everytime you check an item, you need to store de id/position of the item checked (maybe ArrayList<Integer>), this way everytime your getView method is getting called you will look at this class/structure you have created and see it the row needs to be checked or not.
Note: If the row is not checked you will have to call to myCheck->setChecked(false); in order to assure that the row is in a coherent state.
You must use a array or option object to record which position is selected.
And detect the array or option object in getView() in adapter.
So, your need move the code: "view.setBackgroundColor(Color.CYAN)" to getView() method.
You have been bitten by what they say "recycling" issues.
When re-using your views, this kind of problems happens.
There are several methods(for example saving checked positions in an arraylist, ...) to deal with it, but in my opinion the simplest and straight forward solution is using tags.
setTag() and getTag()
Here is a tutorial using it.
Hope it helps.

Android Color Rows

does anyone know how to color the background of each row in a listview as they are created?
I have an arraylist which is pulled from my database and populates a layout with a listview in it.
I suspect there might be a way to do it with a simpleadaptor but cant figure it out.
Any help would be much appreciated :)
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.item_list);
// Read var from Intent
Intent intent= getIntent();
final String ListID = intent.getStringExtra("ListID");
golbalItemID = ListID;
ivAdd = (ImageView) findViewById(R.id.ivAdd);
ivCancel = (ImageView) findViewById(R.id.ivCancel);
tvTotItems = (TextView) findViewById(R.id.tvTotItems);
final myDBClass myDb = new myDBClass(this);
final ArrayList<HashMap<String, String>> MebmerList = myDb.SelectAllItemData(ListID);
myData = myDb.SelectItemData(Integer.parseInt(ListID.toString()));
// listView1
final ListView lisView1 = (ListView)findViewById(R.id.listView1);
registerForContextMenu(lisView1);
MyAdapter sAdap;
sAdap = new MyAdapter(ListItems.this, MebmerList, R.layout.activity_column, new String[] {"Name", "Price", "Quan"}, new int[] {R.id.ColName, R.id.ColTel, R.id.ColQuan});
lisView1.setAdapter(sAdap);
lisView1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> myAdapter, View myView, int position, long mylng) {
int iChk = 0;
// Show Data
String arrData[] = myDb.SelectItemData((MebmerList.get(position).get("ItemID").toString()));
if(arrData != null)
{
iChk = Integer.parseInt(arrData[4]);
}
if(iChk == 1)
{
ischkCheck(Integer.parseInt(MebmerList.get(position).get("ItemID").toString()), 0);
change_color(lisView1, position, 255, 255, 255);
System.out.println("POSITION!ichk=1" + myAdapter.getItemAtPosition(position).toString());
setTitle(myAdapter.getItemAtPosition(position).toString());
}
else if(iChk == 0)
{
ischkCheck(Integer.parseInt(MebmerList.get(position).get("ItemID").toString()), 1);
change_color(lisView1, position, 155, 155, 138);
System.out.println("POSITION!ichk=0" + myAdapter.getItemAtPosition(position).toString());
}
}});
ivAdd.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent newActivity = new Intent(ListItems.this,AddItem.class);
newActivity.putExtra("ListID", ListID);
startActivity(newActivity);
finish();
}
});
ivCancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent newActivity = new Intent(ListItems.this,MenuScreen.class);
startActivity(newActivity);
finish();
}
});
Create an Adapter Class, and control each Row's color in it, then set it as adapter of ListView
Here is a sample code from one of my projects, check getView function:
public class ListAdapter extends BaseAdapter {
private LayoutInflater myInflater;
private List<Poet> list;
public ListAdapter(Context context) {
super();
myInflater = LayoutInflater.from(context);
Log.d("Ganjoor", "Data passed to the adapter.");
}
static class ViewHolder {
TextView tvName;
}
public void setData(List<Poet> list) {
this.list = list;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Poet getItem(int position) {
return (null == list) ? null : list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = myInflater.inflate(R.layout.list_adapter, parent,
false);
holder = new ViewHolder();
holder.tvName = (TextView) convertView.findViewById(R.id.tvName);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvName.setTag(list.get(position).getId());
holder.tvName.setText(list.get(position).getName());
// Log.d("Ganjoor", "Adapter: " + list.get(position).getName());
if (position % 2 == 0) {
convertView.setBackgroundResource(R.drawable.grad_blue);
} else {
convertView.setBackgroundResource(R.drawable.row_style);
}
return convertView;
}
}
As #Nikita Beloglazov states, you can do this by implementing a custom ArrayAdapter, putting your coloring scheme in the getView Override method. See ArrayAdapter doc.

SpannableString regex in a ListView

I have a ListView that I'm binding a collection of strings to, using a custom adapter. I'm also underlining certain keywords in the text. I'm using a SpannableString and a regular expression to underline the words, but I'm wondering if this is the most efficient way to do it? I'm noticing a lot of allocations in the Allocation Tracker of the java.util.regex.Matcher and the regex.util.regex.Pattern classes, which may be causing memory leaks in my app. I know regex's can be expensive, but I'm not sure another way to do what I need to do.
public class Main extends ListActivity
{
private static CustomAdapter adapter = null;
private static List<Keyword> keywords;
private static Matcher matcher;
#Override
public void onCreate(Bundle icicle)
{
List<Item> items = new ArrayList<Item>();
keywords = GetKeywords();
items = GetItems();
adapter = new CustomAdapter();
for (Item item : items)
adapter.addItem(item);
this.setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
/* ADAPTER */
private class CustomAdapter extends BaseAdapter
{
private final List<Item> mData = new ArrayList<Item>();
private final LayoutInflater mInflater;
public CustomAdapter() {
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void addItem(Item item) {
mData.add(item);
}
#Override
public int getCount() {
return mData.size();
}
#Override
public Object getItem(int position) {
return mData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final ViewHolder holder;
final Item item = (Item)this.getItem(position);
if (convertView == null)
{
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.main, parent, false);
holder.text = (TextView)convertView.findViewById(R.id.text);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
holder.text.setText(Highlight(item.getTitle(), keywords, matcher), BufferType.SPANNABLE);
return(convertView);
}
}
static class ViewHolder {
TextView text, date, site;
}
private SpannableString Highlight(String text, List<Keyword> keywords, Matcher matcher)
{
final SpannableString content = new SpannableString(text);
for (Keyword keyword : keywords)
{
matcher = Pattern.compile("\\b" + keyword + "\\b").matcher(text);
if (matcher.find())
{
start = matcher.start();
end = matcher.end();
content.setSpan(new UnderlineSpan(), start, end, 0);
}
}
}
return content;
}
}
You are creating a lot of Patterns and Matchers you don't need. I suggest you create one regex to match all the keywords, like this:
private SpannableString Highlight(String text, List<Keyword> keywords)
{
final SpannableString content = new SpannableString(text);
if (keywords.size() > 0)
{
/* create a regex of the form: \b(?:word1|word2|word3)\b */
StringBuilder sb = ne StringBuilder("\\b(?:").append(keywords.get(0).toString());
for (int i = 1; i < keywords.size(); i++)
{
sb.append("|").append(keywords.get(i).toString());
}
sb.append(")\\b");
Matcher m = Pattern.compile(sb.toString()).matcher(text);
while (m.find())
{
content.setSpan(new UnderlineSpan(), m.start(), m.end(), 0);
}
}
return content;
}
Pattern objects are quite expensive to create, so that's where your real savings will come from. On the other hand, Matchers are relatively cheap, which is why I switched from using a static instance to creating a new one each time.

Categories

Resources