1

"ClassName"文字列属性(Warrior、Hunter、Assassinなど)を持つ80以上の "God"オブジェクトのリストを持つAndroidアプリを開発しています。 )。ToggleButtonフィルタ付きListViewアダプタ

私はClassNameでリストをフィルタリングするToggleButtonsを実装しようとしています。一度に複数のフィルタを使用することができます(例: "Warrior"と "Hunter"を確認するToggleButtonsはClassName "Warrior"または "Hunter"を持つすべてのオブジェクトを表示する必要があります)。

これまでのところ、1つの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

私は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(); 
     } 
} 

私はGodクラスの代わりString Sを記述するためにenumを使用することをお勧めします。なぜこの質問から離れすぎるのかを説明すると、but you can read about it here。私は似たsituatiosのためにした何

+0

これは私の問題を解決しました!あなたの助けをありがとう –

1

は以下の通りです:

私はすべてのデータの配列を持っています。 しかし、リストビューを作成するには、最初のものをフィルタリングして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 

武器の各インスタンスについて、ステータスはこれらの3つのいずれかになります。

トグルに基づくフィルタクリーテリアは、これらの3つの値の任意の組合せにすることができます。

例: 戦士とアサシン: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);を使用してフィルタ整数をStringとして渡し、Integer.parseInt(constraint、2);を使用してフィルタで解析することができます。 – Barthy

+0

@Barthy、私はFilterの使い方について同意しますが、バイナリへの変換を避けて、基数10のすべてを扱うことができます。 – Juan

+0

でも、 'String' /' CharSequence'を解析する必要があります。 – Barthy

関連する問題