1

我正在開發一個Android應用程序,其中包含80多個「上帝」對象,每個對象都有一個「ClassName」字符串屬性(「戰士」,「獵人」,「刺客」等)。帶有ToggleButton篩選器的ListView適配器

我想實現將通過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(); 
     } 
    } 

} 

回答

1

我通過保持所有過濾器的ArrayListAdapter解決了這個問題。

這個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

+0

這解決了我的問題!感謝您的幫助 –

1

我做了一個類似的situatios什麼是以下幾點:

我有所有數據的數組。 但爲了填充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; 
} 

聲明:我還沒有運行代碼,所以它可能有一些錯別字。如果是這樣,讓我知道,我會檢查它。但你仍然可以明白這個想法。

+0

我喜歡二元運算。我會通過在'BaseAdapter'中使用一個真正的'Filter'來擴展你的答案,就像問題一樣。作爲約束,人們可以通過過濾器整數作爲使用'Integer.toBinaryString字符串(INT I);',然後使用'的Integer.parseInt(約束,2)分析它在過濾器中;'。 – Barthy

+0

@Barthy,我同意你關於使用過濾器,但你可以避開轉換爲二進制和基數10 – Juan

+0

處理一切,但你仍然需要解析,並從'String' /'CharSequence',對不對? – Barthy