Searching listview with custom ArrayAdapter - android

I have a listview that has a custom adapter, and I was trying to make it searchable using an Action Item. When I click the search icon in the action bar, the edit text comes up, but when I enter text and click "done" on the keyboard, nothing happens.
Here is the main class:
public class ItemId extends SherlockListActivity {
EditText editsearch;
ArrayAdapter<String> adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context ctx = getApplication();
Resources res = ctx.getResources();
String[] options = res.getStringArray(R.array.item_ids);
String[] ids = res.getStringArray(R.array.item_names);
TypedArray icons = res.obtainTypedArray(R.array.item_images);
adapter = new ItemIDAdapter(ctx, R.layout.idslistitem, ids, options, icons);
setListAdapter(adapter );
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Get the options menu view from menu.xml in menu folder
getSupportMenuInflater().inflate(R.menu.items_menu, menu);
// Locate the EditText in menu.xml
editsearch = (EditText) menu.findItem(R.id.menu_search).getActionView();
// Capture Text in EditText
editsearch.addTextChangedListener(textWatcher);
// Show the search menu item in menu.xml
MenuItem menuSearch = menu.findItem(R.id.menu_search);
menuSearch.setOnActionExpandListener(new OnActionExpandListener() {
// Menu Action Collapse
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Empty EditText to remove text filtering
editsearch.setText("");
editsearch.clearFocus();
return true;
}
// Menu Action Expand
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
// Focus on EditText
editsearch.requestFocus();
// Force the keyboard to show on EditText focus
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
return true;
}
});
// Show the settings menu item in menu.xml
MenuItem menuSettings = menu.findItem(R.id.home);
// Capture menu item clicks
menuSettings.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
Intent intent2 = new Intent(ItemId.this, Home.class);
startActivity(intent2);
return true;
}
});
return true;
}
// EditText TextWatcher
private TextWatcher textWatcher = new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
String text = editsearch.getText().toString()
.toLowerCase(Locale.getDefault());
adapter.getFilter().filter(text);
};
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
};
}
And here is the Adapter class:
public class ItemIDAdapter extends ArrayAdapter<String> implements Filterable {
public LayoutInflater mInflater;
public String[] mStrings;
public String[] mIds;
public TypedArray mIcons;
public int mViewResourceId;
public ItemIDAdapter(Context ctx, int viewResourceId,
String[] strings, String[] ids, TypedArray icons) {
super(ctx, viewResourceId, strings);
mInflater = (LayoutInflater)ctx.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mStrings = strings;
mIds = ids;
mIcons = icons;
mViewResourceId = viewResourceId;
}
#Override
public int getCount() {
return mStrings.length;
}
#Override
public String getItem(int position) {
return mStrings[position];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = mInflater.inflate(mViewResourceId, null);
ImageView iv = (ImageView)convertView.findViewById(R.id.option_icon);
iv.setImageDrawable(mIcons.getDrawable(position));
TextView tv = (TextView)convertView.findViewById(R.id.option_text);
tv.setText(mStrings[position]);
TextView tv1 = (TextView)convertView.findViewById(R.id.itemids);
tv1.setText(mIds[position]);
return convertView;
}
}
If anyone has any idea as to why nothing happens when I search, or knows how to fix it, it'd be greatly appreciated. Thanks!!

You need to implement a custom filter. Have a look at this post here someone else has had a similar problem which he solved: https://stackoverflow.com/a/8258457/2045570

Below is mine code, which is working perfectly:-
public class ExpenditureAdapter extends ArrayAdapter<Expenditure> implements Filterable {
ArrayList<Expenditure> listArray;
ArrayList<Expenditure> filteredlistArray;
private Filter mFilter;
public ExpenditureAdapter(#NonNull Context context, ArrayList<Expenditure> list) {
super(context,0, list);
listArray=list;
filteredlistArray=list;
}
#Override
public int getCount() {
return filteredlistArray.size(); // total number of elements in the list
}
public void add(Expenditure object) {
listArray.add(object);
this.notifyDataSetChanged();
}
public Filter getFilter() {
if (mFilter == null) {
mFilter = new CustomFilter();
}
return mFilter;
}
#Override
public Expenditure getItem(int i) {
return filteredlistArray.get(i); // single item in the list
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
#Override
public long getItemId(int i) {
return i; // index number
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Expenditure expenditure = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.listexpenditure, parent, false);
}
// Lookup view for data population
TextView ExpId = (TextView) convertView.findViewById(R.id.ExpId);
TextView ExDate = (TextView) convertView.findViewById(R.id.ExDate);
TextView ExpAmt = (TextView) convertView.findViewById(R.id.ExpAmt);
TextView ExpDetail = (TextView) convertView.findViewById(R.id.ExpDetail);
// Populate the data into the template view using the data object
ExpId.setText(expenditure.ExpId);
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
String dateTime = dateFormat.format(expenditure.ExpDate);
ExDate.setText(dateTime);
ExpAmt.setText(String.valueOf(expenditure.ExpAmt));
ExpDetail.setText(expenditure.ExpDetail);
return convertView;
}
private class CustomFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if(constraint == null || constraint.length() == 0) {
ArrayList<Expenditure> list = new ArrayList<Expenditure>(listArray);
results.values = list;
results.count = list.size();
} else {
ArrayList<Expenditure> newValues = new ArrayList<Expenditure>();
for(int i = 0; i < listArray.size(); i++) {
Expenditure e_item = listArray.get(i);
if(e_item.ExpDetail.contains(constraint)) {
newValues.add(e_item);
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
filteredlistArray = (ArrayList<Expenditure>) results.values;
notifyDataSetChanged();
}
}
and use it in your code as below:-
private TextWatcher textWatcher = new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
String text = txtSearch.getText().toString()
.toLowerCase(Locale.getDefault());
adapter.getFilter().filter(text);
};
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
};

Related

Android searchView not searching the list until fully scrolled

I have a listview with a custom adapter, and Im trying to use SearchView with a CustomFilter. But the search is not "fully" working.
When I search for something that is on the viewable area of the listview, it is able to search, and all nonviewable area is not being included in the search.
Here is a video on whats going on:
https://youtu.be/2Z9FZMlNmGw
main
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_board_game_list, container, false);
this.listView = (ListView) view.findViewById(R.id.listView);
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this.getContext());
databaseAccess.open();
List<String> boardgamesNames = databaseAccess.getNames();
List<String> urls = databaseAccess.getUrls();
adapter = new bgAdapter(getContext(), R.layout.row_layout);
adapterOriginal = new bgAdapter(getContext(), R.layout.row_layout);
databaseAccess.close();
listView.setAdapter(adapter);
int i = 0;
for(String name: boardgamesNames) {
boardgameListRow data = new boardgameListRow(urls.get(i), boardgamesNames.get(i));
i++;
adapter.add(data);
adapterOriginal.add(data);
}
listView.setDivider(null);
listView.setDividerHeight(0);
searchView = (SearchView)view.findViewById(R.id.searchId);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
if (newText.length() > 0) {
adapter.getFilter().filter(newText);
}
return false;
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
BoardGameListFragment fragment= new BoardGameListFragment();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container,fragment);
fragmentTransaction.commit();
//adapter = adapterOriginal;
return true;
}
});
// Inflate the layout for this fragment
return view;
}
}
Here is the Adapter:
https://github.com/Shank09/AndroidTemp/blob/master/bgAdapter.java
I think you need to call notifyDataSetChanged() in onQueryTextChange
I fixed it, I was using the wrong variable in bgAdapter. Please remove this question if possible.
public class Listbyoperator extends Activity {
ListView lstdetail;
Activity act;
EditText search;
ArrayList<DetailModel> detail=new ArrayList<DetailModel>();
DetailaAdapter dadapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listbyoperator);
act=this;
lstdetail=(ListView) findViewById(R.id.Listbyoperator_detaillist);
search=(EditText) findViewById(R.id.editsearch);
search.setPadding(10, 0, 0, 0);
search.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
String text = search.getText().toString().toLowerCase(Locale.getDefault());
dadapter.filter(text);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
});
DetailModel d=new DetailModel("1","HARDIP","saahi");
detail.add(d);
DetailModel d1=new DetailModel("2","jalpa","sadfsadf");
detail.add(d1);
dadapter=new DetailaAdapter(act, detail);
lstdetail.setAdapter(dadapter);
dadapter.notifyDataSetChanged();
lstdetail.setEnabled(true);
}
}
/*Detail Model*/
public class DetailModel
{
public String d_id,d_name,d_decription;
public String getD_id() {
return d_id;
}
public void setD_id(String d_id) {
this.d_id = d_id;
}
public String getD_name() {
return d_name;
}
public void setD_name(String d_name) {
this.d_name = d_name;
}
public String getD_decription() {
return d_decription;
}
public void setD_decription(String d_decription) {
this.d_decription = d_decription;
}
public DetailModel(String s1,String s2,String s3)
{
this.d_id=s1;
this.d_name=s2;
this.d_decription=s3;
}
}
/*detail adapter */
public class DetailaAdapter extends BaseAdapter{
Context mContext;
private List<DetailModel> data=null;
private ArrayList<DetailModel> arraylist;
private static LayoutInflater inflater=null;
private static String String=null,valid;
public boolean flag=true;
public DetailaAdapter(Context context,List<DetailModel> data)
{
mContext = context;
this.data = data;
inflater = LayoutInflater.from(mContext);
this.arraylist = new ArrayList<DetailModel>();
this.arraylist.addAll(data);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return data.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View vi=convertView;
if(convertView==null)
inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater.inflate(R.layout.list_detail, null);
final TextView t1,t2,t3,t4,t5;
t1=(TextView)vi.findViewById(R.id.list_detail_text1);
t2=(TextView)vi.findViewById(R.id.list_detail_textview2);
t3=(TextView)vi.findViewById(R.id.list_detail_text2);
DetailModel da =new DetailModel(String, String,String);
da=data.get(position);
final String a1,a2,a3;
a1=da.d_id;
a2=da.d_name;
a3=da.d_decription;
t2.setText(a3);//description
t3.setText(a2);//name
return vi;
}
public void filter(String charText)
{
charText = charText.toLowerCase(Locale.getDefault());
data.clear();
if (charText.length() == 0) {
data.addAll(arraylist);
}
else
{
for (DetailModel wp : arraylist)
{
if (wp.getD_decription().toLowerCase(Locale.getDefault()).contains(charText) || wp.getD_name().toLowerCase(Locale.getDefault()).contains(charText))
{
data.add(wp);
}
}
}
notifyDataSetChanged();
}
}

Bypassing the bug in filtering that does not update ListView Android

Here is the code, I used a custom adapter, and applied the Filter method, now the ListView does not update when the backspace key is entered, on when one switches back from an item activity. I read it is a bug in filter, but how do I bypass it, I know of apps that have achieved this kind of setup I want.
public class IndexPageActivity extends Activity implements OnItemClickListener{
ListView listView;
EditText editTextB;
PagesAdapter adapter1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.pageList);
editTextB = (EditText) findViewById(R.id.searchB);
adapter1 = new PagesAdapter(this);
listView.setAdapter(adapter1);
adapter1.notifyDataSetChanged();
listView.setOnItemClickListener(this);
editTextB.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
IndexPageActivity.this.adapter1.getFilter().filter(cs.toString());
adapter1.notifyDataSetChanged();
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) { }
#Override
public void afterTextChanged(Editable arg0) { }
});
}
#Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
Intent i;
String name = adapter1.getItem(position);
Log.d("id", name);
if (name.equals("Item1"))
{
i = new Intent(this, anActivity.class);
startActivity(i);
}
else if (name.equals("Item2"))
{
i = new Intent(this, anActivity2.class);
startActivity(i);
}
}
}
class SingleRow {
String pagedata;
SingleRow(String pagedata){
this.pagedata=pagedata;
}
}
class PagesAdapter extends BaseAdapter implements Filterable{
ArrayList<String> pagelist;
List<String> arrayList;
Context context;
String [] pagedatas;
PagesAdapter(Context c){
context=c;
pagelist = new ArrayList<String>();
Resources res = c.getResources();
pagedatas = res.getStringArray(R.array.pages_data);
for (int i=0;i<463;i++){
pagelist.add(pagedatas[i]);
}
}
#Override
public int getCount() {
return pagelist.size();
}
#Override
public String getItem(int i) {
return pagelist.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewG) {
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row=inflater.inflate(R.layout.single_row,viewG,false);
TextView pagetitle = (TextView) row.findViewById(R.id.textViewRow);
String temp=pagelist.get(i);
pagetitle.setText(temp);
return row;
}
public class filter_here extends Filter{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults Result = new FilterResults();
// if constraint is empty return the original names
if(constraint.length() == 0 ){
Result.values = pagelist;
Result.count = pagelist.size();
return Result;
}
ArrayList<String> Filtered_Names = new ArrayList<String>();
String filterString = constraint.toString().toLowerCase();
String filterableString;
for(int i = 0; i<pagelist.size(); i++){
filterableString = pagelist.get(i);
if(filterableString.toLowerCase().contains(filterString)){
Filtered_Names.add(filterableString);
}
}
Result.values = Filtered_Names;
Result.count = Filtered_Names.size();
return Result;
}
#Override
protected void publishResults(CharSequence constraint,FilterResults results) {
pagelist = (ArrayList<String>) results.values;
notifyDataSetChanged();
}
}
#Override
public Filter getFilter() {
return new filter_here();
}
}
1) Backspace Filtering
In your publishResults, you are modifying your pagelist, so if you press backspace and filter again, pagelist only contains a small portion of the original pagelist entries:
So, you need to keep a copy of your original data! Something like:
List<String> allData;
PagesAdapter(Context c) {
...
allData = pagelist;
...
}
and in your filter method, use the allData object:
for (int i = 0; i < allData.size(); i++) {
filterableString = allData.get(i);
if (filterableString.toLowerCase().contains(filterString)) {
Filtered_Names.add(filterableString);
}
}
and also where you reset your data back to the original:
// if constraint is empty return the original names
if (constraint.length() == 0) {
Result.values = allData;
Result.count = allData.size();
return Result;
}
2) Clear filter after returning from another activity:
This can be done in onResume... Personally, i would clear the text in the editText as to reset the filter like so:
#Override
protected void onResume() {
if (editTextB != null) {
editTextB.setText("");
}
super.onResume();
}
Finally found the bug of the backspace, you had some error in the filter function, that am returning an ArrayList, instead of the List that holds the variable the code should the final code is:
public class IndexPageActivity extends Activity implements OnItemClickListener{
ListView listView;
EditText editTextB;
PagesAdapter adapter1;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.pageList);
editTextB = (EditText) findViewById(R.id.searchB);
adapter1 = new PagesAdapter(this);
listView.setAdapter(adapter1);
adapter1.notifyDataSetChanged();
listView.setOnItemClickListener(this);
editTextB.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence cs, int arg1, int arg2,
int arg3) {
// When user changed the Text
IndexPageActivity.this.adapter1.getFilter().filter(cs.toString());
adapter1.notifyDataSetChanged();
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
}
#Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
// TODO Auto-generated method stub
Intent i;
String name = adapter1.getItem(position);
Log.d("id", name);
if (name.equals("Item1"))
{
i = new Intent(this, anActivity.class);
startActivity(i);
}
else if (name.equals("Item2"))
{
i = new Intent(this, anActivity2.class);
startActivity(i);
}
}
}
class SingleRow {
String pagedata;
SingleRow(String pagedata){
this.pagedata=pagedata;
}
}
class PagesAdapter extends BaseAdapter implements Filterable{
ArrayList<String> pagelist;
List<String> arrayList;
Context context;
String [] pagedatas;
PagesAdapter(Context c){
context=c;
pagelist = new ArrayList<String>();
Resources res = c.getResources();
pagedatas = res.getStringArray(R.array.pages_data);
for (int i=0;i<463;i++){
pagelist.add(pagedatas[i]);
}
arrayList = pagelist;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return arrayList.size();
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
#Override
public String getItem(int i) {
// TODO Auto-generated method stub
return arrayList.get(i);
}
#Override
public long getItemId(int i) {
// TODO Auto-generated method stub
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewG) {
// TODO Auto-generated method stub
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row=inflater.inflate(R.layout.single_row,viewG,false);
TextView pagetitle = (TextView) row.findViewById(R.id.textViewRow);
String temp=arrayList.get(i);
pagetitle.setText(temp);
return row;
}
#Override
public Filter getFilter() {
// TODO Auto-generated method stub
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
arrayList = (List<String>) results.values;
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
ArrayList<String> FilteredArrayNames = new ArrayList<String>();
if (pagelist == null) {
pagelist = new ArrayList<String>(arrayList);
}
if (constraint == null || constraint.length() == 0) {
results.count = pagelist.size();
results.values = pagelist;
} else {
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < pagelist.size(); i++) {
String dataNames = pagelist.get(i);
if (dataNames.toLowerCase().startsWith(constraint.toString())) {
FilteredArrayNames.add(dataNames);
}
}
results.count = FilteredArrayNames.size();
System.out.println(results.count);
results.values = FilteredArrayNames;
Log.e("VALUES", results.values.toString());
}
return results;
}
};
return filter;
}
}
How about putting
adapter1.notifyDataSetChanged();
in onResume() method of the Activity?

How to make a custom Filter for search feature

In my app, I have a list of the user's installed applications and want to create a search function for that list. Right now, here is my coding:
// create new adapter
AppInfoAdapter adapter = new AppInfoAdapter(this, Utilities.getInstalledApplication(this), getPackageManager());
// load list application
mListAppInfo = (ListView)findViewById(R.id.lvApps);
// set adapter to list view
mListAppInfo.setAdapter(adapter);
// search bar
inputSearch = (EditText) findViewById(R.id.inputSearch);
inputSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
// Drag_and_Drop_App.this.adapter.getFilter().filter(cs);
Drag_and_Drop_App.this.adapter.getFilter().filter(cs);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
The issue occurs when I get an error on this line:
Drag_and_Drop_App.this.adapter.getFilter().filter(cs);
It says that "getFilter()" is not defined in my Base Adapter, which is this:
package com.example.awesomefilebuilderwidget;
IMPORTS
public class AppInfoAdapter extends BaseAdapter {
private Context mContext;
private List mListAppInfo;
private PackageManager mPackManager;
public AppInfoAdapter(Context c, List list, PackageManager pm) {
mContext = c;
mListAppInfo = list;
mPackManager = pm;
}
#Override
public int getCount() {
return mListAppInfo.size();
}
#Override
public Object getItem(int position) {
return mListAppInfo.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// get the selected entry
ApplicationInfo entry = (ApplicationInfo) mListAppInfo.get(position);
// reference to convertView
View v = convertView;
// inflate new layout if null
if(v == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
v = inflater.inflate(R.layout.layout_appinfo, null);
}
// load controls from layout resources
ImageView ivAppIcon = (ImageView)v.findViewById(R.id.ivIcon);
TextView tvAppName = (TextView)v.findViewById(R.id.tvName);
TextView tvPkgName = (TextView)v.findViewById(R.id.tvPack);
// set data to display
ivAppIcon.setImageDrawable(entry.loadIcon(mPackManager));
tvAppName.setText(entry.loadLabel(mPackManager));
tvPkgName.setText(entry.packageName);
// return view
return v;
}
#Override
public Filter getFilter() {
// TODO Auto-generated method stub
return filter;
}
}
I added the last part "public Filter..." from looking around on stackoverflow. But now, I need a custom filter for the search. What can I use? (I have already tried one thing but it doesn't work)
The method getFilter() is not defined because your adapter has to implements the Filterable interface, so just add "implements Filterable" on your adapter:
public class AppInfoAdapter extends BaseAdapter implements Filterable {
// your stuff
}
and in your getFilter
#Override
public Filter getFilter() {
if(filter == null) {
filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<ApplicationInfo> myFilteredAppList = new ArrayList<ApplicationInfo>();
constraint = constraint.toString().toLowerCase();
for (ApplicationInfo appInfo : originalListAppInfo) {
String somefield = appInfo.getSomeField();
if (somefield.toLowerCase().contains(constraint.toString())) {
myFilteredAppList.add(appInfo);
}
}
results.count = myFilteredAppList.size();
results.values = myFilteredAppList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mListAppInfo = (List<ApplicationInfo>)results.values;
notifyDataSetChanged();
}
};
}
return filter;
}
notice that I've iterated throuh a copy of the original list (originalListAppInfo), created during the creation of the adapter.
private List<ApplicationInfo> originalListAppInfo;
private List<ApplicationInfo> mListAppInfo;
private Filter filter;
public AppInfoAdapter(Context context, List<ApplicationInfo> listApp) {
this.context = context;
this.originalListAppInfo = this.mListAppInfo = listApp;
}
Hope this help. :)

Searching a custom listview

I was curious on how to make a listview with a custom adapter searchable. I followed a tutorial and got everything set up, but the app crashes when I try to type anything in the EditText. Now I know why the app crashes, I just don't know how to fix it.
Here is the code to my MainActivity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context ctx = getApplication();
Resources res = ctx.getResources();
String[] options = res.getStringArray(R.array.item_ids);
String[] ids = res.getStringArray(R.array.item_names);
TypedArray icons = res.obtainTypedArray(R.array.item_images);
setListAdapter(new ItemIDAdapter(ctx, R.layout.idslistitem, ids, options, icons));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Get the options menu view from menu.xml in menu folder
getSupportMenuInflater().inflate(R.menu.items_menu, menu);
// Locate the EditText in menu.xml
editsearch = (EditText) menu.findItem(R.id.menu_search).getActionView();
// Capture Text in EditText
editsearch.addTextChangedListener(textWatcher);
// Show the search menu item in menu.xml
MenuItem menuSearch = menu.findItem(R.id.menu_search);
menuSearch.setOnActionExpandListener(new OnActionExpandListener() {
// Menu Action Collapse
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Empty EditText to remove text filtering
editsearch.setText("");
editsearch.clearFocus();
return true;
}
// Menu Action Expand
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
// Focus on EditText
editsearch.requestFocus();
// Force the keyboard to show on EditText focus
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
return true;
}
});
// Show the settings menu item in menu.xml
MenuItem menuSettings = menu.findItem(R.id.home);
// Capture menu item clicks
menuSettings.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
Intent intent2 = new Intent(ItemId.this, Home.class);
startActivity(intent2);
return true;
}
});
return true;
}
// EditText TextWatcher
private TextWatcher textWatcher = new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
String text = editsearch.getText().toString()
.toLowerCase(Locale.getDefault());
adapter.getFilter().filter(text);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
};
And here is the code to my custom listview adapter:
public class ItemIDAdapter extends ArrayAdapter<String> {
public LayoutInflater mInflater;
public String[] mStrings;
public String[] mIds;
public TypedArray mIcons;
public int mViewResourceId;
ArrayAdapter<String> adapter;
public ItemIDAdapter(Context ctx, int viewResourceId,
String[] strings, String[] ids, TypedArray icons) {
super(ctx, viewResourceId, strings);
mInflater = (LayoutInflater)ctx.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mStrings = strings;
mIds = ids;
mIcons = icons;
mViewResourceId = viewResourceId;
}
#Override
public int getCount() {
return mStrings.length;
}
#Override
public String getItem(int position) {
return mStrings[position];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = mInflater.inflate(mViewResourceId, null);
ImageView iv = (ImageView)convertView.findViewById(R.id.option_icon);
iv.setImageDrawable(mIcons.getDrawable(position));
TextView tv = (TextView)convertView.findViewById(R.id.option_text);
tv.setText(mStrings[position]);
TextView tv1 = (TextView)convertView.findViewById(R.id.itemids);
tv1.setText(mIds[position]);
return convertView;
}
}
The reason the app crashes when I try to search, is because in the TextWatcher, this line: adapter.getFilter().filter(text); adapter is only defined at the top of my main activity, but it isn't used with my listview at ALL. I'm stuck here and really don't know what to replace adapter with, because ItemIDAdapter doesn't work. Thanks for your help!
Replace
setListAdapter(new ItemIDAdapter(ctx, R.layout.idslistitem, ids, options, icons));
with
adapter = new ItemIDAdapter(ctx, R.layout.idslistitem, ids, options, icons)
setListAdapter(adapter );

How make listview filter on android?

Now i want to make filter but i really don't know how to do it. I've read some tutorials and tried but it still does not work. Please help me!
i want to implement the search functionality.
code of class apdater:
public class PlaceAdapter extends BaseAdapter {
private static ArrayList<Place> searchArrayList;
private LayoutInflater mInflater;
public PlaceAdapter(Context context, ArrayList<Place> results) {
searchArrayList = results;
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return searchArrayList.size();
}
public Object getItem(int position) {
return searchArrayList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.row, null);
holder = new ViewHolder();
holder.txtName = (TextView) convertView
.findViewById(R.id.label_place);
holder.txtAddress = (TextView) convertView
.findViewById(R.id.label_address);
holder.txtPhone = (TextView) convertView
.findViewById(R.id.label_distance);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txtName.setText(searchArrayList.get(position).getName());
holder.txtAddress.setText(searchArrayList.get(position).getAddress());
holder.txtPhone.setText(searchArrayList.get(position).getPhone());
return convertView;
}
static class ViewHolder {
TextView txtName;
TextView txtAddress;
TextView txtPhone;
}
}
code of class activity
public class ServiceDetail extends Activity {
private String DB_NAME = "Danang Travel.sqlite";
private PlaceAdapter adapter = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.servicedetail);
final ArrayList<Place> searchResults = GetSearchResults();
final EditText filterEditText = (EditText) findViewById(R.id.filter_text);
final ListView lvPlace = (ListView) findViewById(R.id.listView1);
adapter = new PlaceAdapter(this, searchResults);
lvPlace.setAdapter(adapter);
lvPlace.setTextFilterEnabled(true);
// Set Focus*****************************************
lvPlace.setFocusableInTouchMode(true);
lvPlace.requestFocus();
lvPlace.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View arg0, boolean arg1) {
// TODO Auto-generated method stub
// arg0.setBackgroundColor(arg1 ? Color.GRAY : Color.BLACK);
// lvPlace.setItemsCanFocus(true);
}
});
// lvPlace.setClickable(true);
/******************************************************/
// filter search
filterEditText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence cs, int arg1, int arg2,
int arg3) {
// When user changed the Text
//ServiceDetail.this.adapter.getFilter().filter(cs);
}
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
lvPlace.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> a, View v, int position,
long id) {
Object o = lvPlace.getItemAtPosition(position);
Place fullObject = (Place) o;
Toast toast = Toast.makeText(ServiceDetail.this,
"You have chosen: " + " " + fullObject.getName(),
Toast.LENGTH_SHORT);
toast.setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
}
});
}
private ArrayList<Place> GetSearchResults() {
ArrayList<Place> results = new ArrayList<Place>();
SQLiteDatabase DB = null;
Intent t = getIntent();
Bundle extra = t.getExtras();
String temp = extra.getString("k");
try {
DB = this.openOrCreateDatabase(DB_NAME, MODE_PRIVATE, null);
Cursor c = DB.rawQuery(
"SELECT Name,Address,TypeID FROM ServiceDetail Where SerID = '"
+ temp + "' ORDER BY Name", null);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
Place k = new Place();
// The Cursor is now set to the right position
String n = c.getString(c.getColumnIndex("Name"));
String a = c.getString(c.getColumnIndex("Address"));
String p = c.getString(c.getColumnIndex("TypeID"));
k.setName(n);
k.setAddress(a);
k.setPhone(p);
results.add(k);
}
} catch (SQLiteException se) {
Log.e(getClass().getSimpleName(),
"Could not create or Open the database");
} finally {
DB.close();
}
return results;
}
}
Now i want to make filter but i really don't know how to do it. I've read some tutorials and tried but it still does not work. Please help me!
Here you go :)
//Firstly here is your edittext on which you want to filter
EditTextfilterText = (EditText) findViewById(R.id.search_box);
filterText.clearComposingText();
//Give the edittext the watcher as a text listener
filterText.addTextChangedListener(filterTextWatcher);
//This will listen to key events such as you entering something inside the edit text
private TextWatcher filterTextWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
//Called after text changed
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
//Called each time you enter something into the edittext to filter your list or whatever
public void onTextChanged(CharSequence s, int start, int before,
int count) {
//Adapter creating code
//......
//Filter calling code
adapter.getFilter().filter(s, new FilterListener() {
#Override
public void onFilterComplete(int count) {
//Just for fun do something here once filtering is done
}
});
}
}
};
Now inside your custom adapter you would have the following:
public Filter getFilter() {
filter = new DrugListFilter();
return filter;
}
private class MyFilterName extends Filter{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults retval = new FilterResults();
ArrayList<something> filt = new ArrayList<something>();
//... Some code to filter your current Adapter data by the constaint
//Pass the results to retval
retval.count = filt.size();
retval.values = filt;
}
//return retval
return retval;
}
//This is called once performFiltering is done
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredItems.clear();
//This is your array of filtered items
filteredItems.addAll((ArrayList)results.values);
doneFilter = true;
//Notify the dataset that it needs to update
notifyDataSetChanged();
}
}

Categories

Resources