如何写的ListView与ArrayAdapter自定义过滤器 [英] How to write a custom filter for ListView with ArrayAdapter

查看:150
本文介绍了如何写的ListView与ArrayAdapter自定义过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个连接到ArrayAdapter,其中艺术家是一个简单的类矿,即只有一个ID和一个名字一个ListView。

I have a ListView which is connected to a ArrayAdapter where Artist is a simple class of mine, that has only an id and a name.

现在我想筛选的ListView,所以我呼吁:

Now I want to filter the ListView so I call:

artistAdapter.getFilter().filter("bla", new Filter.FilterListener() {
    public void onFilterComplete(int count) {
        Log.d(Config.LOG_TAG, "filter complete! count: " + count); // returns 8
        Log.d(Config.LOG_TAG, "adapter count: " + artistAdapter.getCount()); // return 1150
    }
});

第一个调试语句打印的8计数这就是corrent计数开始的喇嘛,但适配器没有得到它时listItems。第二个调试语句打印计数1150项。这是列表中的项目的完整号码。

The first debug statement prints a count of 8. That's the corrent count for listitems that start with "bla" but the adapter does not get it. The second debug statement prints a count 1150 items. That's the complete number of items in the list.

所以,不知何故,该滤波器不知道它已经过滤的基础数据适配器。

So somehow the filter does not tell the adapter that it has filtered the underlying data.

我现在想知道:我有做code东西在我的适配器,以便它从过滤器的更新?我必须写一个自定义过滤器?我有什么做的?

I want to know now: do I have do code something in my adapter so it gets the updates from the filter? Do I have to write a custom filter? What do I have to do?

推荐答案

实际上

我注意到,我应该一直使用'originalItems名单已经建立了新的过滤之一performFiltering。

I noticed that I should have been using 'originalItems' list to build the new filtered one in performFiltering.

这将解决这个问题,您看到有关更换过滤器中的文本的任何问题。例如。您搜索的'面包',然后退格,只是一个'B',你会看到所有的B的。在我原来的职位,你就没有了。

This will fix any issues that you see regarding changing the text in the filter. E.g. you search for 'Bread' then backspace to just a 'B' and you should see all 'B's. In my original post you would not have.

    private class GlycaemicIndexItemAdapter extends ArrayAdapter<GlycaemicIndexItem> {

    private ArrayList<GlycaemicIndexItem> items;
    private ArrayList<GlycaemicIndexItem> originalItems = new ArrayList<GlycaemicIndexItem>();
    private GlycaemicIndexItemFilter filter;
    private final Object mLock = new Object();

    public GlycaemicIndexItemAdapter(Context context, int textViewResourceId, ArrayList<GlycaemicIndexItem> newItems) {
            super(context, textViewResourceId, newItems);
            this.items = newItems;
            cloneItems(newItems);
    }

    protected void cloneItems(ArrayList<GlycaemicIndexItem> items) {
        for (Iterator iterator = items.iterator(); iterator
        .hasNext();) {
            GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next();
            originalItems.add(gi);
        }
    }

    @Override
    public int getCount() {
        synchronized(mLock) {
            return items!=null ? items.size() : 0;  

    }

    @Override
    public GlycaemicIndexItem getItem(int item) {
        GlycaemicIndexItem gi = null;
        synchronized(mLock) {
                gi = items!=null ? items.get(item) : null;

        }
        return gi;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.row, null);
            }

            GlycaemicIndexItem i  = null;
            synchronized(mLock) {
                i = items.get(position);
            }

            if (i != null) {
                    TextView tt = (TextView) v.findViewById(R.id.rowText);
                    TextView bt = (TextView) v.findViewById(R.id.rowText2);
                    if (tt != null) {
                          tt.setText("Name: "+i.getName());                            
                    }
                    if(bt != null){
                          bt.setText("GI Value: " + i.getGlycaemicIndex());
                    }
            }
            return v;
    }
    /**
     * Implementing the Filterable interface.
     */
    public Filter getFilter() {
        if (filter == null) {
            filter = new GlycaemicIndexItemFilter();
        }
        return filter;
    }   

    /**
     * Custom Filter implementation for the items adapter.
     *
     */
    private class GlycaemicIndexItemFilter extends Filter {
        protected FilterResults performFiltering(CharSequence prefix) {
            // Initiate our results object
            FilterResults results = new FilterResults();

            // No prefix is sent to filter by so we're going to send back the original array
            if (prefix == null || prefix.length() == 0) {
                synchronized (mLock) {
                    results.values = originalItems;
                    results.count = originalItems.size();
                }
            } else {
                synchronized(mLock) {
                        // Compare lower case strings
                    String prefixString = prefix.toString().toLowerCase();
                    final ArrayList<GlycaemicIndexItem> filteredItems = new ArrayList<GlycaemicIndexItem>();
                    // Local to here so we're not changing actual array
                    final ArrayList<GlycaemicIndexItem> localItems = new ArrayList<GlycaemicIndexItem>();
                    localItems.addAll(originalItems);
                    final int count = localItems.size();

                    for (int i = 0; i < count; i++) {
                        final GlycaemicIndexItem item = localItems.get(i);
                        final String itemName = item.getName().toString().toLowerCase();

                        // First match against the whole, non-splitted value
                        if (itemName.startsWith(prefixString)) {
                            filteredItems.add(item);
                        } else {} /* This is option and taken from the source of ArrayAdapter
                            final String[] words = itemName.split(" ");
                            final int wordCount = words.length;

                            for (int k = 0; k < wordCount; k++) {
                                if (words[k].startsWith(prefixString)) {
                                    newItems.add(item);
                                    break;
                                }
                            }
                        } */
                    }

                    // Set and return
                    results.values = filteredItems;
                    results.count = filteredItems.size();
                }//end synchronized
            }

            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence prefix, FilterResults results) {
            //noinspection unchecked
            synchronized(mLock) {
                final ArrayList<GlycaemicIndexItem> localItems = (ArrayList<GlycaemicIndexItem>) results.values;
                notifyDataSetChanged();
                clear();
                //Add the items back in
                for (Iterator iterator = localItems.iterator(); iterator
                        .hasNext();) {
                    GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next();
                    add(gi);
                }
            }//end synchronized
        }
    }
}


基本上我建立一个健康和营养应用程序和一个屏幕将具有基于血糖/血糖指数的项目清单。我希望用户能够输入,并具有画面自动筛选。现在,如果你只使用字符串,你得到自动筛选是免费的。我不是,虽然,我有它有自己的属性我自己的自定义类GlycaemicIndexItem。我需要提供我自己的筛选,以确保将要在屏幕上绘制的更新所使用的名单,当用户类型。


Basically I am building a health and nutrition application and one screen will have a list of items based on the glycaemic/glycemic index. I want users to be able to type and have the screen autofilter. Now, if you are only using strings, you get autofiltering for free. I am not though, I have my own custom class GlycaemicIndexItem which has properties on it. I need to provide my own filtering to ensure that the list used to be drawn on screen is updated when the user types.

目前画面是一个简单的ListActivity,具有ListView和一个EditText(其中用户类型)。我们将附上一个TextWatcher这个EditText上,以确保我们的更新通知给它。这意味着,它应该适用于所有设备的用户输入,无论硬或软键盘(我有一个HTC DesireZ和一个老G1)上。

Currently the screen is a simple ListActivity, with a ListView and an EditText (which the user types in). We will attach a TextWatcher to this EditText to ensure that we are notified of updates to it. This means that it should work for all devices regardless of the user typing on a hard or soft keyboard (I have an HTC DesireZ and an old G1).

下面是布局的xml的屏幕/活动(有人能告诉我如何粘贴XML code到这里,因为当我尝试使用code座XML没有得到粘贴/正常显示,但除preTED):

Here is the layout xml for the screen/activity (Can someone tell me how to paste xml code into here, as when I try to use code block xml does not get pasted/displayed properly, but interpreted):

由于我们要显示我们在自定义样式行,我们也有行本身的布局xml文件:

As we want to display our rows in custom style, we also have a layout xml file for the row itself:

下面是code整个活动本身。从ListActivity扩展,这一类有充当适配器,它从ArrayAdapter扩展的内部类。这被实例化在活动的onCreate,并通过简单的字符串列表了。注意它是如何在线路39-40创建。我们对行特殊布局通过时与项目的列表

Here is the code for the entire Activity itself. Extending from ListActivity, this class has an inner class that acts as the adapter, which extends from ArrayAdapter. This is instantiated in the onCreate of the Activity and passed a simple list of strings for now. Pay attention to how it is created on lines 39-40. Our special layout for the row is passed in with the list of items.

键来填充自定义行是在适配器的方法 getView

The key to populating the custom rows is in the adapter's method getView.

我们的适配器类,也有被称为GlycaemicIndexItemFilter自己内心的类,它做的工作,当用户类型。我们的过滤器是通过使用TextWatcher及其方法的 afterTextChanged 绑定到我们的EditText上线43-44。该生产线47的线索,我们如何实现过滤。我们呼吁过滤器,我们的过滤器对象。当我们调用用getFilter在第一时间,我们的过滤器创建行148-149。

Our adapter class also has its own inner class called GlycaemicIndexItemFilter which does the work when a user types. Our filter is bound to our EditText on lines 43-44 by use of a TextWatcher and its method afterTextChanged. The line 47 is the clue as to how we achieve filtering. We call filter, on our filter object. Our filter is created when we call getFilter the first time, line 148-149.

   package com.tilleytech.android.myhealthylife;

     import java.util.ArrayList;
     import java.util.Iterator;

     import android.app.ListActivity;
      import android.content.Context;
     import android.content.res.Resources;
     import android.os.Bundle;
     import android.text.Editable;
      import android.text.TextWatcher;
      import android.view.LayoutInflater;
        import android.view.View;
       import android.view.ViewGroup;
       import android.widget.ArrayAdapter;
       import android.widget.EditText;
       import android.widget.Filter;
       import android.widget.ListView;
       import android.widget.TextView;


        public class GlycaemicIndexAtoZActivity extends ListActivity {
          /** Called when the activity is first created. */
        private GlycaemicIndexItemAdapter giAdapter; 
        private TextWatcher filterTextWatcher;
        private EditText filterText = null;

        @Override
        public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.giatoz);            

        ListView lv = getListView();
        lv.setTextFilterEnabled(true);
        // By using setAdapter method in listview we an add string array in list.
        ArrayList<GlycaemicIndexItem> list = getListItems();

        giAdapter = new GlycaemicIndexItemAdapter(this, R.layout.row, list);
        giAdapter.notifyDataSetChanged();
        setListAdapter(giAdapter);

        filterText = (EditText)findViewById(R.id.GI_AtoZSearchEditText);
        filterTextWatcher = new TextWatcher() {

            public void afterTextChanged(Editable s) {
                giAdapter.getFilter().filter(s); //Filter from my adapter
                giAdapter.notifyDataSetChanged(); //Update my view

            }

            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
            }

            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {

            }

        };
        filterText.addTextChangedListener(filterTextWatcher);
    }

    private ArrayList<GlycaemicIndexItem> getListItems() {
        ArrayList<GlycaemicIndexItem> result = new ArrayList<GlycaemicIndexItem>();

        Resources res = getResources();
        //Get our raw strings
        String[] array = res.getStringArray(R.array.GIList);
        for (int i = 0; i < array.length; i++) {
            GlycaemicIndexItem gi = new GlycaemicIndexItem();
            gi.setName(array[i]);
            gi.setGlycaemicIndex(1);
            result.add(gi);
        }

        return result;
    }

    private class GlycaemicIndexItemAdapter extends ArrayAdapter<GlycaemicIndexItem> {

        private ArrayList<GlycaemicIndexItem> items;
        private ArrayList<GlycaemicIndexItem> originalItems = new ArrayList<GlycaemicIndexItem>();
        private GlycaemicIndexItemFilter filter;
        private final Object mLock = new Object();

        public GlycaemicIndexItemAdapter(Context context, int textViewResourceId, ArrayList<GlycaemicIndexItem> newItems) {
                super(context, textViewResourceId, newItems);
                this.items = newItems;
                cloneItems(newItems);
        }

        protected void cloneItems(ArrayList<GlycaemicIndexItem> items) {
            for (Iterator iterator = items.iterator(); iterator
            .hasNext();) {
                GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next();
                originalItems.add(gi);
            }
        }

        @Override
        public int getCount() {
            synchronized(mLock) {
                return items!=null ? items.size() : 0;  
            }
        }

        @Override
        public GlycaemicIndexItem getItem(int item) {
            GlycaemicIndexItem gi = null;
            synchronized(mLock) {
                    gi = items!=null ? items.get(item) : null;

            }
            return gi;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
                View v = convertView;
                if (v == null) {
                    LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    v = vi.inflate(R.layout.row, null);
                }

                GlycaemicIndexItem i  = null;
                synchronized(mLock) {
                    i = items.get(position);
                }

                if (i != null) {
                        TextView tt = (TextView) v.findViewById(R.id.rowText);
                        TextView bt = (TextView) v.findViewById(R.id.rowText2);
                        if (tt != null) {
                              tt.setText("Name: "+i.getName());                            
                        }
                        if(bt != null){
                              bt.setText("GI Value: " + i.getGlycaemicIndex());
                        }
                }
                return v;
        }
        /**
         * Implementing the Filterable interface.
         */
        public Filter getFilter() {
            if (filter == null) {
                filter = new GlycaemicIndexItemFilter();
            }
            return filter;
        }   

        /**
         * Custom Filter implementation for the items adapter.
         *
         */
        private class GlycaemicIndexItemFilter extends Filter {
            protected FilterResults performFiltering(CharSequence prefix) {
                // Initiate our results object
                FilterResults results = new FilterResults();

                // No prefix is sent to filter by so we're going to send back the original array
                if (prefix == null || prefix.length() == 0) {
                    synchronized (mLock) {
                        results.values = originalItems;
                        results.count = originalItems.size();
                    }
                } else {
                    synchronized(mLock) {
                            // Compare lower case strings
                        String prefixString = prefix.toString().toLowerCase();
                        final ArrayList<GlycaemicIndexItem> filteredItems = new ArrayList<GlycaemicIndexItem>();
                        // Local to here so we're not changing actual array
                        final ArrayList<GlycaemicIndexItem> localItems = new ArrayList<GlycaemicIndexItem>();
                        localItems.addAll(originalItems);
                        final int count = localItems.size();

                        for (int i = 0; i < count; i++) {
                            final GlycaemicIndexItem item = localItems.get(i);
                            final String itemName = item.getName().toString().toLowerCase();

                            // First match against the whole, non-splitted value
                            if (itemName.startsWith(prefixString)) {
                                filteredItems.add(item);
                            } else {} /* This is option and taken from the source of ArrayAdapter
                                final String[] words = itemName.split(" ");
                                final int wordCount = words.length;

                                for (int k = 0; k < wordCount; k++) {
                                    if (words[k].startsWith(prefixString)) {
                                        newItems.add(item);
                                        break;
                                    }
                                }
                            } */
                        }

                        // Set and return
                        results.values = filteredItems;
                        results.count = filteredItems.size();
                    }//end synchronized
                }

                return results;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence prefix, FilterResults results) {
                //noinspection unchecked
                synchronized(mLock) {
                    final ArrayList<GlycaemicIndexItem> localItems = (ArrayList<GlycaemicIndexItem>) results.values;
                    notifyDataSetChanged();
                    clear();
                    //Add the items back in
                    for (Iterator iterator = localItems.iterator(); iterator
                            .hasNext();) {
                        GlycaemicIndexItem gi = (GlycaemicIndexItem) iterator.next();
                        add(gi);
                    }
                }//end synchronized
            }
        }
    }
}

这篇关于如何写的ListView与ArrayAdapter自定义过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆