Lol Me
Lol Me

Reputation: 15

How to add a search bar for a listview?

I wanted to add a search function that filters the ListView and show only the results so I added an EditText and I added to it a TextWatcher and wrote this code MainActivity.this.adapter.getFilter().filter(cs); but it doesn't work it says "Cannot resolve getFilter method" and I do get the fact that there isn't an getFilter method in my BaseAdapter but I don't know how to do it or what I should write and I saw a couple of tutorials but I can't maake it work with my code. P.S: the ListView items are gathered from the internet they are not saved in the app code

Here is MainActivity:

public class MainActivity extends Activity {

private static final String TAG = MainActivity.class.getSimpleName();
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private InterstitialAd interstitial;

// Navigation drawer title
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private List<Category> albumsList;
private ArrayList<NavDrawerItem> navDrawerItems;
private NavDrawerListAdapter adapter;
private LinearLayout DrawerLinear;

@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Log.d("Test", "OnCreate Called");

    mTitle = mDrawerTitle = getTitle();

    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    mDrawerList = (ListView) findViewById(R.id.list_slidermenu);
    DrawerLinear = (LinearLayout) findViewById(R.id.DrawerLinear);

    navDrawerItems = new ArrayList<NavDrawerItem>();

    // Getting the albums from shared preferences
    albumsList = AppController.getInstance().getPrefManger().getCategories();

    // Insert "Recently Added" in navigation drawer first position
    Category recentAlbum = new Category(null,
            getString(R.string.nav_drawer_recently_added));

    albumsList.add(0, recentAlbum);

    // Loop through albums in add them to navigation drawer adapter
    for (Category a : albumsList) {
        navDrawerItems.add(new NavDrawerItem(a.getId(), a.getTitle()));
    }

    mDrawerList.setOnItemClickListener(new SlideMenuClickListener());

    // Setting the nav drawer list adapter
    adapter = new NavDrawerListAdapter(getApplicationContext(),
            navDrawerItems);
    mDrawerList.setAdapter(adapter);

    // Enabling action bar app icon and behaving it as toggle button
    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);
    getActionBar().setIcon(
            new ColorDrawable(getResources().getColor(
                    android.R.color.transparent)));

    mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
            R.drawable.ic_drawer, R.string.app_name, R.string.app_name) {
        public void onDrawerClosed(View view) {
            getActionBar().setTitle(mTitle);
            // calling onPrepareOptionsMenu() to show action bar icons
            invalidateOptionsMenu();
        }

        public void onDrawerOpened(View drawerView) {
            getActionBar().setTitle(mDrawerTitle);
            // calling onPrepareOptionsMenu() to hide action bar icons
            invalidateOptionsMenu();
        }
    };
    mDrawerLayout.setDrawerListener(mDrawerToggle);

    if (savedInstanceState == null) {
        // on first time display view for first nav item
        displayView(0);
    }

    final EditText inputSearch = (EditText) findViewById(R.id.inputSearch);

    inputSearch.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            // TODO Auto-generated method stub
            //You should use the adapter in NavigationDrawerFragment
            MainActivity.this.adapter.getFilter().filter(cs); // Doesn't work, gives an error "Cannot resolve getFilter method"

        }

        @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

        }
    });

}

and here is my Adapter:

public class NavDrawerListAdapter extends BaseAdapter{

private Context context;
private ArrayList<NavDrawerItem> navDrawerItems;

public NavDrawerListAdapter(Context context,
        ArrayList<NavDrawerItem> navDrawerItems) {
    this.context = context;
    this.navDrawerItems = navDrawerItems;
}

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

@Override
public Object getItem(int position) {
    return navDrawerItems.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater mInflater = (LayoutInflater) context
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        convertView = mInflater.inflate(R.layout.drawer_list_item, null);
    }

    TextView txtTitle = (TextView) convertView.findViewById(R.id.title);

    txtTitle.setText(navDrawerItems.get(position).getTitle());

    return convertView;
}
}

Upvotes: 1

Views: 2105

Answers (3)

1lb3r
1lb3r

Reputation: 508

You can add a SearchView in your toolbar/actionbar in order to let the user search(filter) the listview. Here an example (http://javapapers.com/android/android-searchview-action-bar-tutorial/). Then you can filter using a Filterable adapter following what Danail Alexiev suggested to you or simply filtering the source of the adapter and updating the adapter from outside.

Upvotes: 0

Ognev Zair
Ognev Zair

Reputation: 1626

First you should implement your adapter from Filterable

public class NavDrawerListAdapter extends BaseAdapter implements Filterable

and override getFilter method:

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence searchText) {
            //by searchText you should filter here
            FilterResults result = new FilterResults();

             // here your filtering 
             // filling result 

            return result;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {

         // here your filterResults
            clear();
            addAll(filterResults.values);
            notifyDataSetChanged();
        }
    };
}

Second in your Activity declare Filter object

 private Filter filter;

in onCreate initialize filter:

adapter = new NavDrawerListAdapter(getApplicationContext(),
        navDrawerItems);
 // getting filter from adapter
filter = adapter.getFilter();

and in your onTextChanged:

@Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub
        //You should use the adapter in NavigationDrawerFragment
       filter.filter(cs); 
    }

Thats all:)

Upvotes: 0

Danail Alexiev
Danail Alexiev

Reputation: 7792

You should implement the Filterable interface in your custom adapter. It is not implemented by BaseAdapter.

Edit: This is a more complete example:

public class FiltarableAdapter extends BaseAdapter implements Filterable {

    // keep the full data here. This is needed to not loose it while filtering
    private List<SomeObject> originalData;
    // keep the data you want to show to the user here
    private List<SomeObject> data;

    // skip adapter methods 

    // we will use an instance of this to perform the filtering
    private class AdapterFilter implements Filter {

        FilterResults performFiltering(CharSequence constraint) {
            // use the constraint to filter your data in this method and create a list containing the result
            List<SomeObject> filteredData = ...
            FilterResults result = new FilterResults();
            result.count = filteredData.size();
            result.object = filteredData;
        }

        void publishResults(CharSequence constraint, Filter.FilterResults results) {
            // here you get the search results and you should use them to update your UI
            // for brevity of the example, we just replace the current adapter data with the result object
            FilterableAdapter.this.data = results.object;
            FilterableAdapter.this.notifyDataSetChanged();
        }
    }

    public Filter getFilter() {
        return new AdapterFilter();
    }
}

Basically, you define your filter internally in the adapter and return a new instance to the client that calls getFilter(). In the filter itself you need to do the search in your data and, when you have the results, swap the resulting data set with the current data set. You will need to keep the original unfiltered data set as well, so you are able to quickly restore the list if the filter is cleared.

Hope this helps.

Upvotes: 3

Related Questions