带有ToggleButton过滤器的ListView适配器

时间:2017-04-13 00:28:54

标签: android listview android-adapter togglebutton android-togglebutton

我正在开发一款Android应用程序,其中包含80多个“God”对象列表,每个对象都有一个“ClassName”字符串属性(“Warrior”,“Hunter”,“Assassin”等)。

我正在尝试实现将按ClassName过滤列表的ToggleButtons。应该允许一次使用多个过滤器(例如:检查“Warrior”和“Hunter”ToggleButtons应该显示所有具有ClassName“Warrior”或“Hunter”的对象。)

到目前为止,我只能根据一个ClassName约束过滤列表。任何帮助实现这一点将不胜感激!

这是我的主要片段:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View myView =  inflater.inflate(R.layout.home,null);

        final ArrayList<God> gods = getGods();

        lv = (ListView) myView.findViewById(R.id.home_list);
        sv = (SearchView) myView.findViewById(R.id.home_search);
        sv.setQueryHint("Search Gods...");
        mage = (ToggleButton) myView.findViewById(R.id.mage);
        assassin = (Button) myView.findViewById(R.id.assassin);

        adapter = new GodAdapter(getActivity(), gods);
        lv.setAdapter(adapter);

        mage.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked){
                    //Include all mages
                }
                else {
                    //Remove all mages

                }
            }
        });

assassin.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if(isChecked){
                        //Include all assassins
                    }
                    else {
                        //Remove all assassins

                    }
                }
            });

(...other buttons...)



        sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            public boolean onQueryTextSubmit(String query) {
                return false;
            }
            public boolean onQueryTextChange(String query) {
                adapter.getFilter().filter(query);
                return false;
            }
        });

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
                String name = adapter.getItem(position).getName();

                for(int i = 0; i < gods.size(); i++) {
                    if(gods.get(i).getName().equals(name))
                    {
                        Fragment myFragment = new TabFragment();
                        myFragment.setArguments(createGodBundle(gods.get(i)));
                        replaceFragment(myFragment);
                        hideSoftKeyboard(getActivity());
                        break;
                    }
                }
            }
        });

        return myView;
    }

这是我的GodAdapter:

public class GodAdapter extends BaseAdapter implements Filterable {

    Context c;
    ArrayList<God> gods;
    ArrayList<God> filterList;
    CustomFilter filter;

    public GodAdapter(Context c, ArrayList<God> gods) {
        this.c = c;
        this.gods = gods;
        this.filterList = gods;
    }

    public int getCount() {
        return gods.size();
    }

    public God getItem(int position) {
        return gods.get(position);
    }

    public long getItemId(int position) {
        return gods.indexOf(getItem(position));
    }

    public View getView(int position, View convertView, ViewGroup parent) {


        LayoutInflater inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if(convertView == null)
            convertView = inflater.inflate(R.layout.god_selection, null);

        TextView name = (TextView) convertView.findViewById(R.id.god_name);
        ImageView image = (ImageView) convertView.findViewById(R.id.god_image);
        ImageView pantheon =(ImageView) convertView.findViewById(R.id.pantheon);
        ImageView type =(ImageView) convertView.findViewById(R.id.type);

        name.setText(gods.get(position).getName());
        image.setImageResource(gods.get(position).getImage());
        pantheon.setImageResource(gods.get(position).getPantheonIcon());
        type.setImageResource(gods.get(position).getClassIcon());

        return convertView;
    }

    public Filter getFilter() {
        if(filter == null)
            filter = new CustomFilter();
        return filter;
    }


    //Inner class for filtering
    class CustomFilter extends Filter {

        protected FilterResults performFiltering(CharSequence constraint) {

            FilterResults results = new FilterResults();

            if(constraint != null && constraint.length() > 0)
            {
                constraint = constraint.toString().toUpperCase();
                ArrayList<God> filters = new ArrayList<God>();

                for(int i = 0; i < filterList.size(); i++)
                {
                    if(filterList.get(i).getName().toUpperCase().contains(constraint))
                    {
                        God god = new God(filterList.get(i).getName(), filterList.get(i).getTitle(), filterList.get(i).getNameString(), filterList.get(i).getImage(),
                                filterList.get(i).getPantheon(), filterList.get(i).getPantheonIcon(), filterList.get(i).getClassName(), filterList.get(i).getClassIcon(), filterList.get(i).getType(),
                                filterList.get(i).getHealth(), filterList.get(i).getMana(), filterList.get(i).getDamage(), filterList.get(i).getProtPhys(), filterList.get(i).getProtMag(), filterList.get(i).getSpeed(),
                                filterList.get(i).getHp5(), filterList.get(i).getMp5(), filterList.get(i).getAttackSpeed());
                        filters.add(god);
                    }
                }
                results.count = filters.size();
                results.values = filters;
            } else {
                results.count = filterList.size();
                results.values = filterList;
            }
            return results;
        }

        protected void publishResults(CharSequence constraint, FilterResults results) {
            gods = (ArrayList<God>) results.values;
            notifyDataSetChanged();
        }
    }

}

2 个答案:

答案 0 :(得分:1)

我通过在ArrayList中保留Adapter个所有过滤器来解决此问题。

这个ArrayList将成为您的约束,您可以通过检查元素是否包含God的类来过滤元素。

示例:

public class GodAdapter extends BaseAdapter implements Filterable {

    ...
    ArrayList<God> gods;
    ArrayList<God> filteredGods;
    private ArrayList<String> classFilters;

    ...

    public boolean toggleFilter(String class) {
        if (classFilters.contains(class)) {
            classFilters.remove(class);
            return false;
        } else {
            classFilters.add(class);
            return true;
        }
    }

    ...

    class CustomFilter extends Filter {

        protected FilterResults performFiltering(CharSequence constraint) {

            FilterResults results = new FilterResults();

            if(classFilters.size() > 0){
                ArrayList<God> filteredList = new ArrayList<God>();

                for(int i = 0; i < filterList.size(); i++){
                    God god = filterList.get(i);
                    if(classFilters.contains(god.getName().toUpperCase())){
                        filteredList.add(god);
                    }
                }
                results.count = filteredList.size();
                results.values = filteredList;
            } else {
                results.count = filterList.size();
                results.values = filterList;
            }
            return results;
        }

        protected void publishResults(CharSequence constraint, FilterResults results) {
            // IMPORTANT publish the results to a separate list
            filteredGods = (ArrayList<God>) results.values;
            notifyDataSetChanged();
        }
}

我建议使用enum来描述God类,而不是String。解释为什么离这个问题太远了but you can read about it here

答案 1 :(得分:1)

我对类似情况的所作所为如下:

我有一个包含所有数据的数组。 但是为了填充listview,我通过过滤第一个数组来生成第二个数组。

对于过滤器,我使用非独占键的组合。

public static fianl STATUS_WARRIOR = 1; //binary: 00000001
public static fianl STATUS_HUNTER = 2;  //binary: 00000010
public static fianl STATUS_ASSASIN = 4; //binary: 00000100

对于每个武器实例,它的状态将是这三个中的一个。

基于切换的过滤器可以是这三个值的任何组合。

实施例: 战士和阿萨辛:00000101 亨特和阿萨辛:00000110

(您只需要'|'(或)有效值

因此,您的切换将定义0到7之间的数字

对于过滤,您只需要检查武器'&'(和)过滤器的状态。如果它不是0,则将它包含在您将传递给列表视图的数组中。

private ArrayList<Weapon> allWeaponsArrayList = new ArrayList<>();

// Set all the weapons perhaps in onCreate() inside allWeaponsArrayList.

int statusFromToggles = 0;
statusFromToggles = toggleWarriorOn? statusFromToggles | STATUS_WARRIOR: statusFromToggles ; 
statusFromToggles = toggleHunterOn? statusFromToggles | STATUS_HUNTER: statusFromToggles ; 
statusFromToggles = toggleAssasinOn? statusFromToggles | STATUS_ASSASIN: statusFromToggles ; 

public ArrayList<Weapon> filterWeapons(statusFromToggles){
    ArrayList<Weapon> rtn = new ArrayList<Weapon>();
    for(Weapon weapon : allWeaponsArrayList){
        if(weapon.getStatus() & statusFromToggles){
            rtn.add(weapon);
        }
     }
     return rtn;
}

免责声明:我没有运行代码,因此可能会有一些拼写错误。如果是这样,请告诉我,我会检查一下。但你仍然可以得到这个想法。