2012-01-09 22 views
38

मैं कस्टम CustomerAdapter हैएंड्रॉयड AutoCompleteTextView कस्टम एडाप्टर छानने काम नहीं कर रहा

public class CustomerAdapter extends ArrayAdapter<Customer> { 
    private final String MY_DEBUG_TAG = "CustomerAdapter"; 
    private ArrayList<Customer> items; 
    private int viewResourceId; 

    public CustomerAdapter(Context context, int viewResourceId, ArrayList<Customer> items) { 
     super(context, viewResourceId, items); 
     this.items = items; 
     this.viewResourceId = viewResourceId; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     View v = convertView; 
     if (v == null) { 
      LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = vi.inflate(viewResourceId, null); 
     } 
     Customer customer = items.get(position); 
     if (customer != null) { 
      TextView customerNameLabel = (TextView) v.findViewById(R.id.customerNameLabel); 
      if (customerNameLabel != null) { 
       customerNameLabel.setText(String.valueOf(customer.getName())); 
      } 
     } 
     return v; 
    } 
} 

और customer_auto लेआउट

<?xml version="1.0" encoding="utf-8"?> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/customerNameLabel" 
    android:layout_width="fill_parent" android:layout_height="fill_parent" 
    android:padding="10dp" android:textSize="16sp" 
    android:textColor="#000"> 
</TextView> 

और पर अपने public void onCreate

AutoCompleteTextView customerAutoComplete = (AutoCompleteTextView) findViewById(R.id.autocomplete_customer); 
CustomerAdapter customerAdapter = new CustomerAdapter(this, R.layout.customer_auto, customerList); 
customerAutoComplete.setAdapter(customerAdapter); 

और Customer.java

public class Customer implements Parcelable { 

    private int id; 
    private String name = ""; 

    public Customer() { 
     // TODO Auto-generated constructor stub 
    } 

    /** 
    * This will be used only by the MyCreator 
    * 
    * @param source 
    */ 
    public Customer(Parcel source) { 
     /* 
     * Reconstruct from the Parcel 
     */ 
     id = source.readInt(); 
     name = source.readString(); 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public int getId() { 
     return this.id; 
    } 

    public String getName() { 
     return this.name; 
    } 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeInt(id); 
     dest.writeString(name); 
    } 

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 

     @Override 
     public Customer createFromParcel(Parcel source) { 
      return new Customer(source); 
     } 

     @Override 
     public Customer[] newArray(int size) { 
      return new Customer[size]; 
      // TODO Auto-generated method stub 
     } 

    }; 

    @Override 
    public String toString() { 
     return this.name; 
    } 

} 

लेकिन ऑटो सुझाव बॉक्स सही ढंग से फ़िल्टर नहीं करता है। उदाहरण के लिए; अगर मैं an टाइप करता हूं तो परीक्षण बॉक्स में br से शुरू होने वाले ग्राहक दिखा रहे हैं!

+0

मुझे लगता है कि आपको उस ग्राहक की जांच करने की आवश्यकता है जिसे आप ग्राहक एडाप्टर में भेज रहे हैं। इसमें गलत डेटा हो सकता है। आप कहां से उस सूची को बना रहे हैं? – kosa

+0

नहीं, 'ग्राहक सूची' में सही डेटा है, जब मैंने इसे 'स्पिनर' में उपयोग किया तो यह सही ढंग से दिखाया गया –

+0

क्या आपने सुझाव बॉक्स में प्रदर्शित करने से पहले उन्हें प्रिंट किया था?setText से ठीक पहले? जो कुछ सुराग दे सकता है। साथ ही मैं ऐप को अनइंस्टॉल करने और पुनः इंस्टॉल करने का सुझाव दूंगा। – kosa

उत्तर

104

मैं करने के लिए अति-सवारी एडाप्टर

यहाँ की getFilter() विधि है, sacoskun

public class CustomerAdapter extends ArrayAdapter<Customer> { 
    private final String MY_DEBUG_TAG = "CustomerAdapter"; 
    private ArrayList<Customer> items; 
    private ArrayList<Customer> itemsAll; 
    private ArrayList<Customer> suggestions; 
    private int viewResourceId; 

    public CustomerAdapter(Context context, int viewResourceId, ArrayList<Customer> items) { 
     super(context, viewResourceId, items); 
     this.items = items; 
     this.itemsAll = (ArrayList<Customer>) items.clone(); 
     this.suggestions = new ArrayList<Customer>(); 
     this.viewResourceId = viewResourceId; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     View v = convertView; 
     if (v == null) { 
      LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = vi.inflate(viewResourceId, null); 
     } 
     Customer customer = items.get(position); 
     if (customer != null) { 
      TextView customerNameLabel = (TextView) v.findViewById(R.id.customerNameLabel); 
      if (customerNameLabel != null) { 
//    Log.i(MY_DEBUG_TAG, "getView Customer Name:"+customer.getName()); 
       customerNameLabel.setText(customer.getName()); 
      } 
     } 
     return v; 
    } 

    @Override 
    public Filter getFilter() { 
     return nameFilter; 
    } 

    Filter nameFilter = new Filter() { 
     @Override 
     public String convertResultToString(Object resultValue) { 
      String str = ((Customer)(resultValue)).getName(); 
      return str; 
     } 
     @Override 
     protected FilterResults performFiltering(CharSequence constraint) { 
      if(constraint != null) { 
       suggestions.clear(); 
       for (Customer customer : itemsAll) { 
        if(customer.getName().toLowerCase().startsWith(constraint.toString().toLowerCase())){ 
         suggestions.add(customer); 
        } 
       } 
       FilterResults filterResults = new FilterResults(); 
       filterResults.values = suggestions; 
       filterResults.count = suggestions.size(); 
       return filterResults; 
      } else { 
       return new FilterResults(); 
      } 
     } 
     @Override 
     protected void publishResults(CharSequence constraint, FilterResults results) { 
      ArrayList<Customer> filteredList = (ArrayList<Customer>) results.values; 
      if(results != null && results.count > 0) { 
       clear(); 
       for (Customer c : filteredList) { 
        add(c); 
       } 
       notifyDataSetChanged(); 
      } 
     } 
    }; 

} 
+12

उपर्युक्त कोड मूल सूची –

+0

को संशोधित करता है, मुझे फ़िल्टर पर इंगित करने के लिए बहुत बहुत धन्यवाद। आईएमएचओ यह एक बड़ी डिजाइन त्रुटि है कि यह लेल को ओवरराइड करने के लिए बहुत अधिक काम है, वहां एक सरल getLable() विधि होनी चाहिए जिसे फ़िल्टर में कंप्यूशन के लिए इस्तेमाल किया जाना चाहिए। – rekire

+0

हां वास्तव में यह मूल सूची को संशोधित करता है। –

3

करने के लिए धन्यवाद उपरोक्त कोड में publisHResults() विधि समवर्ती संशोधन अपवाद देता कोड जो मेरे लिए काम किया है

@Override 
protected void publishResults(CharSequence constraint, FilterResults results) { 
    ArrayList<Customer> filteredList = (ArrayList<Customer>) results.values; 
    ArrayList<Customer> customerList=new ArrayList<Customer>(); 
    if (results != null && results.count > 0) { 
     clear(); 
     for (Customer c : filteredList) { 
      customerList.add(c); 
     } 
     Iterator<Customer> customerIterator=getResult.iterator(); 
     while (customerIterator.hasNext()) { 
      Customer customerIterator=customerIterator.next(); 
      add(customerIterator); 
     } 
     notifyDataSetChanged(); 
    } 
} 
+5

आप getResult विधि से कहां से पुनर्प्राप्त कर रहे हैं? – krisDrOid

1

मैं kno नहीं है: .... हम के रूप में कोड को संशोधित करने के लिए है डब्ल्यू जहां आप getResult पुनर्प्राप्त कर रहे हैं। मुझे लगता है कि इस मामले में समाधान समवर्ती संशोधन नहीं है:

@Override 
protected void publishResults(CharSequence constraint, FilterResults results) { 
    ArrayList<Customer> filteredList = (ArrayList<Customer>) results.values; 
    ArrayList<Customer> customerList=new ArrayList<Customer>(); 
    if (results != null && results.count > 0) { 
     clear(); 

try{ 
      for (Customer c : filteredList) { 
       customerList.add(c); 
      } 
}catch(Exception e){ 
Log.e("PEEEETAAAAAAAA", "AutoCompletaError: "+e.getMessage()+" "+e.getCause()+" "+e.getLocalizedMessage()); 
      } 

     Iterator<Customer> customerIterator=customerList.iterator(); 
     while (customerIterator.hasNext()) { 
      Customer customerIterator=customerIterator.next(); 
      add(customerIterator); 
     } 
     notifyDataSetChanged(); 
    } 
} 
41

यह मेरा समाधान है। मुझे लगता है कि यह स्वीकार्य एक की तुलना में थोड़ा क्लीनर (3 अलग, भ्रमित ऐरेलिस्ट का उपयोग नहीं करता) है, और इसमें अधिक विकल्प हैं।

यहां कुछ परीक्षण और त्रुटि के बाद मैंने काम किया है। यह है, अगर उपयोगकर्ता प्रकार बैकस्पेस भी काम करना चाहिए, क्योंकि यह mCustomers से मूल प्रविष्टियों को दूर नहीं करता:

public class CustomerAdapter extends ArrayAdapter<Customer> { 
    private LayoutInflater layoutInflater; 
    List<Customer> mCustomers; 

    private Filter mFilter = new Filter() { 
     @Override 
     public String convertResultToString(Object resultValue) { 
      return ((Customer)resultValue).getName(); 
     } 

     @Override 
     protected FilterResults performFiltering(CharSequence constraint) { 
      FilterResults results = new FilterResults(); 

      if (constraint != null) { 
       ArrayList<Customer> suggestions = new ArrayList<Customer>(); 
       for (Customer customer : mCustomers) { 
        // Note: change the "contains" to "startsWith" if you only want starting matches 
        if (customer.getName().toLowerCase().contains(constraint.toString().toLowerCase())) { 
         suggestions.add(customer); 
        } 
       } 

       results.values = suggestions; 
       results.count = suggestions.size(); 
      } 

      return results; 
     } 

     @Override 
     protected void publishResults(CharSequence constraint, FilterResults results) { 
      clear(); 
      if (results != null && results.count > 0) { 
       // we have filtered results 
       addAll((ArrayList<Customer>) results.values); 
      } else { 
       // no filter, add entire original list back in 
       addAll(mCustomers); 
      } 
      notifyDataSetChanged(); 
     } 
    }; 

    public CustomerAdapter(Context context, int textViewResourceId, List<Customer> customers) { 
     super(context, textViewResourceId, customers); 
     // copy all the customers into a master list 
     mCustomers = new ArrayList<Customer>(customers.size()); 
     mCustomers.addAll(customers); 
     layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View view = convertView; 

     if (view == null) { 
      view = layoutInflater.inflate(R.layout.customerNameLabel, null); 
     } 

     Customer customer = getItem(position); 

     TextView name = (TextView) view.findViewById(R.id.customerNameLabel); 
     name.setText(customer.getName()); 

     return view; 
    } 

    @Override 
    public Filter getFilter() { 
     return mFilter; 
    } 
} 
+0

यह समाधान समझना आसान है। – Seenu69

+0

सबसे अच्छा समाधान कभी भी –

+0

यह कोड सुझाव में सभी डेटा दिखा रहा है? स्वत: पूर्ण ड्रॉप डाउन में मेरा मतलब है – umerk44

2

हो सकता है कि यह बहुत देर हो चुकी है, तो आप न इन सभी कार्यों के ओवरराइड करने के लिए की जरूरत है, केवल समारोह ओवरराइड करने के लिए है:

public View getView(int position, View convertView, ViewGroup parent) { 
    View v = convertView; 
    if (v == null) { 
     LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     v = vi.inflate(viewResourceId, null); 
    } 
    Customer customer = getItem(position); 
    if (customer != null) { 
     TextView customerNameLabel = (TextView) v.findViewById(R.id.customerNameLabel); 
     if (customerNameLabel != null) { 
      customerNameLabel.setText(String.valueOf(customer.getName())); 
     } 
    } 
    return v; 
} 

पर विचार मैं बदलने के लिए:

Customer customer = items.get(position); 
Customer customer = getItem(position); 

वेतन ध्यान, आप नए ListItems घोषित नहीं करना चाहिए,

private ArrayList<Customer> items; 

क्योंकि ArrayAdapter अपनी ही mObjects के साथ काम करता है, और नहीं आपकी आइटम सूची इस सूची को फ़िल्टर, तो तुम GetItem समारोह आइटम तक पहुँचने के लिए उपयोग करना चाहिए। तो आपके ArrayFilter को लिखने का कोई कारण नहीं है।

+0

यह सही उत्तर है, परिणाम गलत हैं क्योंकि वस्तुओं को बेस क्लास सूची में फ़िल्टर किया गया है, न कि कस्टम सदस्य सूची पर। एक बार 'आइटम' सदस्य को हटा दिया जाता है और 'getItem (pos)' का उपयोग किया जाता है, तो परिणाम सही होंगे जैसे मूल 'ArrayAdapter' का उपयोग किया गया था। – SagiLow

0

मेरे पास गैर-अद्यतन और उपरोक्त उत्तर से समस्याएं संशोधित करें। मैंने इस समस्या के साथ इस समस्या को ठीक किया है।

public class AdapterAutoCompleteTextView extends ArrayAdapter<ItemWord> { 

    private int LayoutID; 
    private int TextViewID; 

    private LayoutInflater Inflater; 

    private List<ItemWord> ObjectsList; 

    public AdapterAutoCompleteTextView(Context ActivityContext, int ResourceID, int TextViewResourceID, List<ItemWord> WordList) { 
     super(ActivityContext, ResourceID, TextViewResourceID, new ArrayList<ItemWord>()); 

     LayoutID = ResourceID; 
     TextViewID = TextViewResourceID; 

     ObjectsList = WordList; 

     Inflater = LayoutInflater.from(ActivityContext); 
    } 

    @Override 
    public View getView(int Position, View ConvertView, ViewGroup Parent) { 
     ItemWord Word = getItem(Position); 

     if(ConvertView == null) { 
      ConvertView = Inflater.inflate(LayoutID, null); 

      ResultHolder Holder = new ResultHolder(); 

      Holder.ResultLabel= (TextView) ConvertView.findViewById(TextViewID); 

      ConvertView.setTag(Holder); 
     } 

     ResultHolder Holder = (ResultHolder) ConvertView.getTag(); 

     Holder.ResultLabel.setText(Word.getSpelling()); 

     return ConvertView; 
    } 

    @Override 
    public Filter getFilter() { 
     return CustomFilter; 
    } 

    private Filter CustomFilter = new Filter() { 
     @Override 
     public CharSequence convertResultToString(Object ResultValue) { 
      return ((ItemWord) ResultValue).getSpelling(); 
     } 

     @Override 
     protected FilterResults performFiltering(CharSequence Constraint) { 
      FilterResults ResultsFilter = new FilterResults(); 

      ArrayList<ItemWord> OriginalValues = new ArrayList<ItemWord>(ObjectsList); 

      if(Constraint == null || Constraint.length() == 0){ 
       ResultsFilter.values = OriginalValues; 
       ResultsFilter.count = OriginalValues.size(); 
      } else { 
       String PrefixString = Constraint.toString().toLowerCase(); 

       final ArrayList<ItemWord> NewValues = new ArrayList<ItemWord>(); 

       for(ItemWord Word : OriginalValues){ 
        String ValueText = Word.getSpelling().toLowerCase(); 

        if(ValueText.startsWith(PrefixString)) 
         NewValues.add(Word); 
       } 

       ResultsFilter.values = NewValues; 
       ResultsFilter.count = NewValues.size(); 
      } 

      return ResultsFilter; 
     } 

     @Override 
     protected void publishResults(CharSequence Constraint, FilterResults Results) { 
      clear(); 

      if(Results.count > 0) 
       addAll(((ArrayList<ItemWord>) Results.values)); 
      else 
       notifyDataSetInvalidated(); 
     } 
    }; 

    private static class ResultHolder { 
     TextView ResultLabel; 
    } 

} 

इस गैर अद्यतन के लिए सबसे महत्वपूर्ण रेखा है और मूल सूची मुद्दे को संशोधित:

super(ActivityContext, ResourceID, TextViewResourceID, new ArrayList<ItemWord>()); 

विशेष रूप से उन लोगों के

सुपर (ActivityContext, RESOURCEID, TextViewResourceID, नई ArrayList());

मुझे आशा है कि इस समाधान तुम्हारी मदद की जाएगी :)

4

इसके बजाय एडाप्टर में getFilter() विधि अधिभावी की, बस हम UserDefined वस्तु (ग्राहक) के toString() ओवरराइड कर सकते हैं। toString() में केवल फ़िल्टर को फ़िल्टर करने के लिए आवश्यक फ़ील्ड पर वापस लौटें। यह मेरे लिए काम किया।

मेरे उदाहरण में मैं नाम पर आधारित फिल्टरिंग हूँ:

public class Customer{ 
    private int id; 
    private String name; 

    @Override 
    public String toString() { 
     return this.name; 
    } 
} 
1

मुझे आशा है कि इस पोस्ट भविष्य में इसी तरह कस्टम कार्यक्षमता के कार्यान्वयन के साथ लोगों को मदद मिलेगी।

public class TagSuggestionsAdapter extends ArrayAdapter<String> implements Filterable 

ArrayAdapter विस्तार कम बॉयलरप्लेट कोड के लिए: मैं एडाप्टर के अपने संस्करण मेरी माइक्रोब्लॉगिंग अनुप्रयोग में टैग सुझाव प्रदर्शित करने के लिए प्रयोग किया जाता है पर इस आधार पर। फ़िल्टर व्यवहार को बाद में बदलने के लिए फ़िल्टर करने योग्य कार्यान्वित करना। (इसे बाद में फ़िल्टर किए गए परिणामों के साथ एक सूची हो जाएगा यह भी एक सूची जब notifyDataSetChanged बुला कि ध्यान में रखा जाना होगा के लिए एक संदर्भ है -

private List<String> allTags; 
    private List<String> tagSuggestions;  
    private Context context; 

public TagSuggestionsAdapter(List<String> initialTagSuggestions, List<String> allTags, 
          Context context) { 
    super(context, R.layout.item_tag_suggestion, initialTagSuggestions); 
    this.tagSuggestions = initialTagSuggestions; 
    this.allTags = allTags; 
    this.context = context; 
} 

निर्माता में मूल रूप से आप एक सूची है कि शुरू में प्रदर्शित किया जाएगा पारित करने के लिए की जरूरत है()) और स्पष्ट रूप से एक सूची जिस पर आप अपने फ़िल्टरिंग (मेरे मामले में सभी टैग) का आधार बना सकते हैं। मैं getView() में लेआउट मुद्रास्फीति के लिए संदर्भ भी पारित कर रहा हूं।

@NonNull 
    @Override 
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) { 

     ViewHolder viewHolder;  

     if (convertView == null) { 
      convertView = LayoutInflater.from(context) 
        .inflate(R.layout.item_tag_suggestion, parent, false); 
      viewHolder = new ViewHolder(convertView); 
      convertView.setTag(viewHolder); 
     } else { 
      viewHolder = (ViewHolder) convertView.getTag(); 
     } 

     viewHolder.tagSuggestionTextView.setText(tagSuggestions.get(position)); 

     return convertView; 
    } 

    static class ViewHolder { 

     @BindView(R.id.tag_suggestion_text_view) 
     TextView tagSuggestionTextView; 

     ViewHolder(View itemView) { 
      ButterKnife.bind(this, itemView); 
     } 
    } 

ऊपर आप एक कस्टम दृश्य लेआउट को बढ़ाने के लिए Butterknife से थोड़ी मदद के साथ एक साधारण दृश्य धारक पैटर्न देख सकते हैं।

@NonNull 
    @Override 
    public Filter getFilter() { 
     return new Filter() { 

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 
       if (constraint != null) { 
        List<String> filteredTags = filterTagSuggestions(constraint.toString(), allTags); 
        FilterResults filterResults = new FilterResults(); 
        filterResults.values = filteredTags; 
        filterResults.count = filteredTags.size(); 
        return filterResults; 
       } else { 
        return new FilterResults(); 
       } 
      } 

      @Override 
      protected void publishResults(CharSequence constraint, FilterResults results) { 
       tagSuggestions.clear(); 
       if (results != null && results.count > 0) { 
        List<?> filteredTags = (List<?>) results.values; 
        for (Object filteredTag : filteredTags) { 
         if (filteredTag instanceof String) { 
          tagSuggestions.add((String) filteredTag); 
         } 
        } 
       } 
       notifyDataSetChanged(); 
      } 
     }; 
    } 

यह कम से कम बॉयलरप्लेट कोड है जिसे मैं लिख सकता हूं। आपकी एकमात्र चिंता विधि filterTagSuggestions है जो उपयोगकर्ता (CharSequence constraint) से इनपुट के आधार पर टैग की फ़िल्टर की गई सूची वापस करनी चाहिए। उम्मीद है कि संक्षेप में जरूरी जानकारी और संगठित जानकारी थोड़ी सी।

संबंधित मुद्दे