【问题标题】:ListView Adapter with ToggleButton Filters带有 ToggleButton 过滤器的 ListView 适配器
【发布时间】:2017-09-08 22:51:13
【问题描述】:

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

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

到目前为止,我只能根据一个 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();
        }
    }

}

【问题讨论】:

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


    【解决方案1】:

    我通过在Adapter 中保留所有过滤器的ArrayList 解决了这个问题。

    然后这个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 类而不是Strings。解释为什么离这个问题太远了,but you can read about it here

    【讨论】:

      【解决方案2】:

      我在类似情况下所做的如下:

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

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

      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 之间的数字

      要进行过滤,您只需检查武器'&amp;' 的状态(和)过滤器标准。如果它不是 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;
      }
      

      免责声明:我没有运行代码,所以它可能有一些拼写错误。如果是这样,请告诉我,我会检查它。但你仍然可以理解。

      【讨论】:

      • 我喜欢二进制操作。我会通过在BaseAdapter 中使用真正的Filter 来扩展您的答案,就像在问题中一样。作为约束,可以使用Integer.toBinaryString(int i); 将过滤器整数作为字符串传递,然后使用Integer.parseInt(constraint, 2); 在过滤器中对其进行解析。
      • @Barthy,我同意你关于使用过滤器的观点,但你可以避免转换为二进制并处理基数 10 中的所有内容。
      • 但是你仍然需要解析到String / CharSequence,对吧?
      • 是的,将参数传递给Filter对象,然后返回使用Filter内部的参数。
      猜你喜欢
      • 2014-09-06
      • 2012-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多