2012-12-22 180 views
0

檢查:過濾自定義適配器返回不正確的結果

screenshot

我想實現我的ListView過濾器。但是我面臨着一個很奇怪的問題。如果我在EditText中鍵入字母T,則ListView正在填寫從B,J開始的名稱。請幫忙。

public class MyCustomAdapter extends BaseAdapter implements Filterable { 

Context mContext; 
private LayoutInflater mInflater; 
SparseBooleanArray mSparseBooleanArray; 
private ArrayList<Map<String,String>> mAdapData = new ArrayList<Map<String, String>>(); 
private ArrayList<Map<String,String>> mOriginalData = new ArrayList<Map<String, String>>(); 

public MyCustomAdapter(Context mContext) { 
    mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    mSparseBooleanArray = new SparseBooleanArray(); 
} 

public ArrayList<String> getCheckedItems() { 
    ArrayList<String> mTempArry = new ArrayList<String>(); 
    for (int i = 0; i < mAdapData.size(); i++) { 
     if (mSparseBooleanArray.get(i)) { 
      Map<String, String> map = (Map<String, String>) mAdapData.get(i); 
      final String numbr = map.get("Phone").toString(); 
      mTempArry.add(numbr); 
     } 
    } 
    return mTempArry; 
} 

@Override 
public int getCount() { 
    return this.mAdapData.size(); 
} 

public void addItem(String paramString1, String paramString2) { 
    Map<String, String> NameNumber = new HashMap<String, String>(); 
    NameNumber.put("Name", paramString1); 
    NameNumber.put("Phone", paramString2); 
    this.mAdapData.add(NameNumber); 
    this.mOriginalData.add(NameNumber); 
    notifyDataSetChanged(); 
} 

@SuppressWarnings("unchecked") 
public Object getItem(int paramInt) { 
    return (ArrayList<Map<String, String>>) this.mAdapData.get(paramInt); 
} 

@Override 
public long getItemId(int paramInt) { 
    return paramInt; 
} 

@Override 
public View getView(final int paramInt, View paramView, ViewGroup paramViewGroup) { 

    ViewHolder viewHolder; 

    if (paramView == null) { 
     viewHolder = new ViewHolder(); 
     paramView = mInflater.inflate(R.layout.multiplecontactview, null); 
     viewHolder.tvName = (TextView) paramView.findViewById(R.id.txtContactName); 
     viewHolder.tvNumber = (TextView) paramView.findViewById(R.id.txtContactNumber); 
     viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1); 
     viewHolder.cb.setTag(paramInt); 
     viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt)); 
     viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener); 
     viewHolder.tvName.setTextColor(Color.BLACK); 
     viewHolder.tvNumber.setTextColor(Color.BLACK); 
     for (int i = 0; i < mAdapData.size(); i++) { 
      Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt); 
      final String name = map.get("Name").toString(); 
      Log.e("Name", name); 
      final String numbr = map.get("Phone").toString(); 
      Log.e("Number", numbr); 
      viewHolder.tvName.setText(name); 
      viewHolder.tvNumber.setText(numbr); 
     } 
     paramView.setTag(viewHolder); 
    } else { 
     viewHolder = (ViewHolder) paramView.getTag(); 
    }  
    return paramView; 
} 

OnCheckedChangeListener mCheckedChangeListener = new OnCheckedChangeListener() { 
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
     mSparseBooleanArray.put((Integer) buttonView.getTag(), isChecked); 
    } 
}; 

public static class ViewHolder { 
    TextView tvName; 
    TextView tvNumber; 
    CheckBox cb; 
} 

@Override 
public Filter getFilter() { 
    return new MyContactFilter(); 
} 

@SuppressLint("DefaultLocale") 
private class MyContactFilter extends Filter { 

    @Override 
    protected FilterResults performFiltering(CharSequence constraint) { 
     FilterResults results = new FilterResults(); 
     ArrayList<Map<String, String>> mFilteredData = new ArrayList<Map<String, String>>(); 

     if (!TextUtils.isEmpty(constraint)) { 
      for(int i = 0; i < mAdapData.size(); i++) { 
       Map<String, String> map = (Map<String, String>) mAdapData.get(i); 
       final String names = map.get("Name").toString(); 
       final String numbr = map.get("Phone").toString(); 
       if(names.toLowerCase().contains(constraint.toString().toLowerCase())) { 
        Map<String, String> FilNameNumber = new HashMap<String, String>(); 
        FilNameNumber.put("Name", names); 
        FilNameNumber.put("Phone", numbr); 
        mFilteredData.add(FilNameNumber); 
       } 
      } 
      results.values = mFilteredData; 
      results.count = mFilteredData.size(); 

     } else { 
      synchronized (mOriginalData) { 
       results.values = mOriginalData; 
       results.count = mOriginalData.size(); 
      } 
     } 
     return results; 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    protected void publishResults(CharSequence cs, FilterResults fr) { 
     mAdapData = (ArrayList<Map<String, String>>) fr.values; 
     notifyDataSetChanged(); 
    } 
} 
} 

回答

3

你的問題都來自你的方式設置的getView()方法,以及如何在SparseBooleanArray設定的檢查項目。我編輯了適配器的代碼,它現在應該可以工作。主要變化在OnCheckedChangeListener字段中:

public class MyCustomAdapter extends BaseAdapter implements Filterable { 

    private Context mContext; 
    private LayoutInflater mInflater; 
    private SparseBooleanArray mSparseBooleanArray; 
    // from where do you get the data? 
    private ArrayList<Map<String, String>> mAdapData = new ArrayList<Map<String, String>>(); 
    private ArrayList<Map<String, String>> mOriginalData = new ArrayList<Map<String, String>>(); 

    public MyCustomAdapter(Context mContext) { 
     mInflater = (LayoutInflater) mContext 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     mSparseBooleanArray = new SparseBooleanArray(); 
    } 

    public ArrayList<String> getCheckedItems() { 
     ArrayList<String> mTempArry = new ArrayList<String>(); 
     for (int i = 0; i < mAdapData.size(); i++) { 
      if (mSparseBooleanArray.get(i)) { 
       Map<String, String> map = (Map<String, String>) mAdapData 
         .get(i); 
       final String numbr = map.get("Phone"); 
       mTempArry.add(numbr); 
      } 
     } 
     return mTempArry; 
    } 

    @Override 
    public int getCount() { 
     return this.mAdapData.size(); 
    } 

    public void addItem(String paramString1, String paramString2) { 
     Map<String, String> NameNumber = new HashMap<String, String>(); 
     NameNumber.put("Name", paramString1); 
     NameNumber.put("Phone", paramString2); 
     mAdapData.add(NameNumber); 
     mOriginalData.add(NameNumber); 
     notifyDataSetChanged(); 
    } 

    @SuppressWarnings("unchecked") 
    public Object getItem(int paramInt) { 
     return (ArrayList<Map<String, String>>) this.mAdapData.get(paramInt); 
    } 

    @Override 
    public long getItemId(int paramInt) { 
     return paramInt; 
    } 

    @Override 
    public View getView(final int paramInt, View paramView, 
      ViewGroup paramViewGroup) { 
     ViewHolder viewHolder; 
     if (paramView == null) { 
      viewHolder = new ViewHolder(); 
      paramView = mInflater.inflate(R.layout.adapters_specialfilterrow, 
        paramViewGroup, false); 
      viewHolder.tvName = (TextView) paramView 
        .findViewById(R.id.textView1); 
      viewHolder.tvNumber = (TextView) paramView 
        .findViewById(R.id.textView2); 
      viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1); 
      paramView.setTag(viewHolder); 
     } else { 
      viewHolder = (ViewHolder) paramView.getTag(); 
     } 
     viewHolder.cb.setTag(paramInt); 
     viewHolder.cb.setOnCheckedChangeListener(null); 
     viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt)); 
     viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener); 
     viewHolder.tvName.setTextColor(Color.BLACK); 
     viewHolder.tvNumber.setTextColor(Color.BLACK); 
     Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt); 
     final String name = map.get("Name"); 
     final String numbr = map.get("Phone"); 
     viewHolder.tvName.setText(name); 
     viewHolder.tvNumber.setText(numbr); 
     return paramView; 
    } 

    OnCheckedChangeListener mCheckedChangeListener = new OnCheckedChangeListener() { 
     public void onCheckedChanged(CompoundButton buttonView, 
       boolean isChecked) { 
      // get the item from the current mAdapData 
      Map<String, String> item = mAdapData.get((Integer) buttonView 
        .getTag()); 
      int position = -1; 
      // see where is the item placed in the mOriginalData and use that 
      // position 
      for (int i = 0; i < mOriginalData.size(); i++) { 
       final Map<String, String> tmp = mOriginalData.get(i); 
       if (tmp.get("Name").toLowerCase().equals(item.get("Name").toLowerCase())) { 
        position = i; 
        break; 
       } 
      } 
      mSparseBooleanArray.put(position, isChecked); 
     } 
    }; 

    public static class ViewHolder { 
     TextView tvName; 
     TextView tvNumber; 
     CheckBox cb; 
    } 

    @Override 
    public Filter getFilter() { 
     return new MyContactFilter(); 
    } 

    @SuppressLint("DefaultLocale") 
    private class MyContactFilter extends Filter { 

     @Override 
     protected FilterResults performFiltering(CharSequence constraint) { 
      FilterResults results = new FilterResults(); 
      ArrayList<Map<String, String>> mFilteredData = new ArrayList<Map<String, String>>(); 

      if (!TextUtils.isEmpty(constraint)) { 
       for (int i = 0; i < mAdapData.size(); i++) { 
        Map<String, String> map = (Map<String, String>) mAdapData 
          .get(i); 
        final String names = map.get("Name"); 
        final String numbr = map.get("Phone"); 
        if (names.toLowerCase().contains(
          constraint.toString().toLowerCase())) { 
         Map<String, String> FilNameNumber = new HashMap<String, String>(); 
         FilNameNumber.put("Name", names); 
         FilNameNumber.put("Phone", numbr); 
         mFilteredData.add(FilNameNumber); 
        } 
       } 
       results.values = mFilteredData; 
       results.count = mFilteredData.size(); 
      } else { 
       synchronized (mOriginalData) { 
        results.values = mOriginalData; 
        results.count = mOriginalData.size(); 
       } 
      } 
      return results; 
     } 

     @SuppressWarnings("unchecked") 
     @Override 
     protected void publishResults(CharSequence cs, FilterResults fr) { 
      mAdapData = (ArrayList<Map<String, String>>) fr.values; 
      notifyDataSetChanged(); 
     } 
    } 
} 
+0

非常感謝你 –

+0

認真,我已經發布了相同的答案,並得到選擇...... :( –

+0

@androiddeveloper你的答案只是解決方案的一部分(這是我包括在我的答案(我承認,在),但OnCheckedChangeListener監聽器的變化也很重要,並最終解決了用戶的所有問題。 – Luksprog

1

getView()方法,你沒有更新UI有過濾結果的值。 因此它返回了舊的結果的意見。

就在返回paramView之前,將視圖的數據更新爲篩選結果中的數據,並將其從viewHolder的準備中移除,因爲這隻會被調用幾次。


編輯: 這裏是我對代碼的修正。我認爲這將解決這個問題:

@Override 
public View getView(final int paramInt, View paramView, ViewGroup paramViewGroup) { 

ViewHolder viewHolder; 

if (paramView == null) { 
    viewHolder = new ViewHolder(); 
    paramView = mInflater.inflate(R.layout.multiplecontactview, null); 
    viewHolder.tvName = (TextView) paramView.findViewById(R.id.txtContactName); 
    viewHolder.tvNumber = (TextView) paramView.findViewById(R.id.txtContactNumber); 
    viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1); 
    viewHolder.tvName.setTextColor(Color.BLACK); 
    viewHolder.tvNumber.setTextColor(Color.BLACK); 
    paramView.setTag(viewHolder); 
    viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener); 
} else { 
    viewHolder = (ViewHolder) paramView.getTag(); 
}  
viewHolder.cb.setTag(paramInt); 
viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt)); 


Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt); 
final String name = map.get("Name").toString(); 
Log.e("Name", name); 
final String numbr = map.get("Phone").toString(); 
Log.e("Number", numbr); 
viewHolder.tvName.setText(name); 
viewHolder.tvNumber.setText(numbr); 

return paramView; 
} 

編輯: 這裏是我如何處理過濾的樣品:

@Override 
public Filter getFilter() 
    { 
    final Filter filter=new Filter() 
    { 
     @Override 
     protected FilterResults performFiltering(final CharSequence constraint) 
     { 
     _lastFilterConstraint=constraint; 
     if(TextUtils.isEmpty(constraint)) 
      return null; 
     final String constraintToCheck=constraint.toString().toLowerCase(Locale.getDefault()); 
     final FilterResults results=new FilterResults(); 
     // <- here i do the filtering itself and later put the results into "results" 
     results.values=values; 
     results.count=values.size(); 
     return results; 
     } 

     @SuppressWarnings("unchecked") 
     @Override 
     protected void publishResults(final CharSequence constraint,final FilterResults results) 
     { 
     _filteredItems==null ? null : (ArrayList<Item>)results.values; 
     notifyDataSetChanged(); 
     } 
    }; 
    return filter; 
    } 

@Override 
public int getCount() 
    { 
    if(_filteredItems!=null) 
    return _filteredItems.size(); 
    return _originalItems.size(); 
    } 

@Override 
public Item getItem(final int position) 
    { 
    if(_filteredItems!=null) 
    { 
    if(position<_filteredItems.size()) 
     return _filteredItems.get(position); 
    return null; 
    } 
    if(position<_originalItems.size()) 
    return _originalItems.get(position); 
    return null; 
    } 

@Override 
public View getView(final int position,final View convertView,final ViewGroup parent) 
    { 
    final View inflatedView; 
    final ViewHolder viewHolder; 
    if(convertView==null) 
    { 
    //<- here i inflate the view into the inflatedView 
    } 
    else 
    { 
    inflaterView=convertView; 
    viewHolder=(ViewHolder)inflaterView.getTag(); 
    } 
    // <- here i use getItem and update the view according to its data . 
    return inflaterView; 
    } 
+0

但爲什麼當我搜索字母T時,listview正在填充包含字母B的名稱? –

+0

@ user1822826因爲你只在'convertView'爲'null'(最初)時設置了'TextViews'。過濾很可能會顯示以前的行沒有設置新數據的「TextViews」。在你完成過濾之後,你應該看看'mAdapData'包含了什麼。 – Luksprog

+0

@Luksprog請告訴我如何解決這個錯誤。 –

1

我還實施了在我的應用程序過濾器列表視圖。爲此,我只需要一段代碼。檢查一下,如果有幫助。

editText.addTextChangedListener(new TextWatcher() { 

      public void onTextChanged(CharSequence arg0, int arg1, int arg2, 
        int arg3) { 

      } 
      public void beforeTextChanged(CharSequence arg0, int arg1, 
        int arg2, int arg3) { 

      } 
      public void afterTextChanged(Editable arg0) { 
       sendToList.this.adapter.getFilter().filter(arg0); 

      } 
     }); 
+0

這將適用於我的適配器?我正在使用'ArrayList >來填充'listview' –

+0

不確定,但你可以試試。我用它作爲單個對象。 –

相關問題