我正在开发一款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();
}
}
}
答案 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;
}
免责声明:我没有运行代码,因此可能会有一些拼写错误。如果是这样,请告诉我,我会检查一下。但你仍然可以得到这个想法。