SearchView के साथ RecyclerView को कैसे फ़िल्टर करें


319

मैं SearchViewसमर्थन पुस्तकालय से लागू करने का प्रयास कर रहा हूं । मैं चाहता हूं कि उपयोगकर्ता को फिल्मों में SearchViewफिल्टर करने के लिए उपयोग करना चाहिए ।ListRecyclerView

मैंने अब तक कुछ ट्यूटोरियल्स का अनुसरण किया है और मैंने इसे इसमें जोड़ा SearchViewहै ActionBar, लेकिन मुझे यकीन नहीं है कि यहाँ से कहाँ जाना है। मैंने कुछ उदाहरण देखे हैं लेकिन उनमें से कोई भी परिणाम नहीं दिखा रहा है जैसे ही आप लिखना शुरू करते हैं।

यह मेरा है MainActivity:

public class MainActivity extends ActionBarActivity {

    RecyclerView mRecyclerView;
    RecyclerView.LayoutManager mLayoutManager;
    RecyclerView.Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mAdapter = new CardAdapter() {
            @Override
            public Filter getFilter() {
                return null;
            }
        };
        mRecyclerView.setAdapter(mAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

और यह मेरा है Adapter:

public abstract class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> implements Filterable {

    List<Movie> mItems;

    public CardAdapter() {
        super();
        mItems = new ArrayList<Movie>();
        Movie movie = new Movie();
        movie.setName("Spiderman");
        movie.setRating("92");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Doom 3");
        movie.setRating("91");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers");
        movie.setRating("88");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers 2");
        movie.setRating("87");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers 3");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Noah");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman 2");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman 3");
        movie.setRating("86");
        mItems.add(movie);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_card_item, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Movie movie = mItems.get(i);
        viewHolder.tvMovie.setText(movie.getName());
        viewHolder.tvMovieRating.setText(movie.getRating());
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder{

        public TextView tvMovie;
        public TextView tvMovieRating;

        public ViewHolder(View itemView) {
            super(itemView);
            tvMovie = (TextView)itemView.findViewById(R.id.movieName);
            tvMovieRating = (TextView)itemView.findViewById(R.id.movieRating);
        }
    }
}

जवाबों:


913

परिचय

चूंकि यह आपके प्रश्न से वास्तव में स्पष्ट नहीं है कि वास्तव में आपको क्या परेशानी हो रही है, इसलिए मैंने इस सुविधा को कैसे लागू किया जाए, इस बारे में त्वरित रूप से लिखा; यदि आपके पास अभी भी प्रश्न पूछने के लिए स्वतंत्र हैं।

मेरे पास इस GitHub रिपॉजिटरी में जो कुछ भी मैं यहां बात कर रहा हूं उसका एक उदाहरण है ।
यदि आप उदाहरण प्रोजेक्ट के बारे में अधिक जानना चाहते हैं तो प्रोजेक्ट होमपेज पर जाएँ ।

किसी भी मामले में परिणाम कुछ इस तरह दिखना चाहिए:

डेमो छवि

यदि आप पहले डेमो ऐप के साथ खेलना चाहते हैं, तो आप इसे प्ले स्टोर से इंस्टॉल कर सकते हैं:

गूगल प्ले से इसे प्राप्त करें

वैसे भी शुरू करने देता है।


की स्थापना SearchView

फ़ोल्डर में res/menuनामक एक नई फ़ाइल बनाएँ main_menu.xml। इसमें एक आइटम जोड़ें और actionViewClassटू सेट करें android.support.v7.widget.SearchView। चूंकि आप समर्थन लाइब्रेरी का उपयोग कर रहे हैं, इसलिए आपको actionViewClassविशेषता सेट करने के लिए समर्थन लाइब्रेरी के नामस्थान का उपयोग करना होगा । आपकी xml फ़ाइल कुछ इस तरह दिखनी चाहिए:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item android:id="@+id/action_search"
          android:title="@string/action_search"
          app:actionViewClass="android.support.v7.widget.SearchView"
          app:showAsAction="always"/>

</menu>

आपके Fragmentया Activityआपको सामान्य रूप से इस मेनू xml को बढ़ाना है, तो आप इसके लिए देख सकते हैं MenuItemजिसमें शामिल है SearchViewऔर OnQueryTextListenerजिसे हम पाठ में दर्ज किए गए परिवर्तनों को सुनने के लिए उपयोग करने जा रहे हैं SearchView:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);

    final MenuItem searchItem = menu.findItem(R.id.action_search);
    final SearchView searchView = (SearchView) searchItem.getActionView();
    searchView.setOnQueryTextListener(this);

    return true;
}

@Override
public boolean onQueryTextChange(String query) {
    // Here is where we are going to implement the filter logic
    return false;
}

@Override
public boolean onQueryTextSubmit(String query) {
    return false;
}

और अब SearchViewउपयोग करने के लिए तैयार है। हम फ़िल्टर लॉजिक को बाद में लागू कर देंगे onQueryTextChange()जब हम समाप्त कर देंगे Adapter


की स्थापना Adapter

सबसे पहला और महत्वपूर्ण यह है कि मैं इस उदाहरण के लिए जिस मॉडल वर्ग का उपयोग करने जा रहा हूं:

public class ExampleModel {

    private final long mId;
    private final String mText;

    public ExampleModel(long id, String text) {
        mId = id;
        mText = text;
    }

    public long getId() {
        return mId;
    }

    public String getText() {
        return mText;
    }
}

यह सिर्फ अपने बुनियादी मॉडल है जिसमें एक पाठ प्रदर्शित करेगा है RecyclerView। यह वह लेआउट है जिसे मैं टेक्स्ट प्रदर्शित करने के लिए उपयोग करने जा रहा हूं:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="model"
            type="com.github.wrdlbrnft.searchablerecyclerviewdemo.ui.models.ExampleModel"/>

    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackground"
        android:clickable="true">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="8dp"
            android:text="@{model.text}"/>

    </FrameLayout>

</layout>

जैसा कि आप देख सकते हैं कि मैं डेटा बाइंडिंग का उपयोग करता हूं। यदि आपने कभी छूटने से पहले डेटा बाइंडिंग के साथ काम नहीं किया है! यह बहुत सरल और शक्तिशाली है, हालांकि मैं यह नहीं बता सकता कि यह इस उत्तर के दायरे में कैसे काम करता है।

यह वह जगह है ViewHolderके लिए ExampleModelवर्ग:

public class ExampleViewHolder extends RecyclerView.ViewHolder {

    private final ItemExampleBinding mBinding;

    public ExampleViewHolder(ItemExampleBinding binding) {
        super(binding.getRoot());
        mBinding = binding;
    }

    public void bind(ExampleModel item) {
        mBinding.setModel(item);
    }
}

फिर कुछ खास नहीं। यह सिर्फ इस लेआउट में मॉडल वर्ग को बांधने के लिए डेटा बाइंडिंग का उपयोग करता है जैसा कि हमने ऊपर के लेआउट xml में परिभाषित किया है।

अब हम अंततः वास्तव में दिलचस्प हिस्से पर आ सकते हैं: एडेप्टर लिखना। मैं Adapterइसके जवाब के लिए प्रासंगिक भागों पर ध्यान केंद्रित करने जा रहा हूं और इसके मूल कार्यान्वयन को छोड़ रहा हूं ।

लेकिन पहले एक बात है जो हमें करनी है: SortedListकक्षा।


SortedList

SortedListजो का हिस्सा है एक पूरी तरह से अद्भुत उपकरण है RecyclerViewपुस्तकालय। यह Adapterडेटा सेट के परिवर्तनों के बारे में सूचित करने का ध्यान रखता है और इसलिए यह एक बहुत ही कुशल तरीका है। केवल एक चीज जो आपको करने की आवश्यकता है वह तत्वों के एक आदेश को निर्दिष्ट करना है। आपको एक ऐसा compare()तरीका लागू करने की आवश्यकता है जो दो तत्वों की तुलना करता है SortedListजैसे कि ए Comparator। लेकिन छँटाई के बजाय Listइसका उपयोग वस्तुओं को क्रमबद्ध करने के लिए किया जाता है RecyclerView!

SortedListसाथ सूचना का आदान Adapterएक के माध्यम से Callbackवर्ग है जो आप को लागू करने के लिए है:

private final SortedList.Callback<ExampleModel> mCallback = new SortedList.Callback<ExampleModel>() {

    @Override
    public void onInserted(int position, int count) {
         mAdapter.notifyItemRangeInserted(position, count);
    }

    @Override
    public void onRemoved(int position, int count) {
        mAdapter.notifyItemRangeRemoved(position, count);
    }

    @Override
    public void onMoved(int fromPosition, int toPosition) {
        mAdapter.notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onChanged(int position, int count) {
        mAdapter.notifyItemRangeChanged(position, count);
    }

    @Override
    public int compare(ExampleModel a, ExampleModel b) {
        return mComparator.compare(a, b);
    }

    @Override
    public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
        return oldItem.equals(newItem);
    }

    @Override
    public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
        return item1.getId() == item2.getId();
    }
}

जैसे कॉलबैक के शीर्ष पर तरीकों में onMoved, onInsertedआदि आप कॉल करने के लिए बराबर सूचित अपने की विधि है Adapter। तल पर तीन विधियाँ compare, areContentsTheSameऔर areItemsTheSameआपको यह प्रदर्शित करना होगा कि आप किस प्रकार की वस्तुओं को प्रदर्शित करना चाहते हैं और किस क्रम में इन वस्तुओं को स्क्रीन पर दिखाना चाहिए।

आइए इन तरीकों को एक-एक करके देखें:

@Override
public int compare(ExampleModel a, ExampleModel b) {
    return mComparator.compare(a, b);
}

यह वह compare()विधि है जिसके बारे में मैंने पहले बात की थी। इस उदाहरण में मैं केवल Comparatorदो मॉडलों की तुलना करने के लिए कॉल पास कर रहा हूं । यदि आप चाहते हैं कि आइटम स्क्रीन पर वर्णानुक्रम में दिखाई दें। यह तुलनित्र इस तरह दिख सकता है:

private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
    @Override
    public int compare(ExampleModel a, ExampleModel b) {
        return a.getText().compareTo(b.getText());
    }
};

अब अगली विधि पर एक नज़र डालते हैं:

@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
    return oldItem.equals(newItem);
}

इस पद्धति का उद्देश्य यह निर्धारित करना है कि क्या किसी मॉडल की सामग्री बदल गई है। यह SortedListनिर्धारित करने के लिए इसका उपयोग करता है कि क्या परिवर्तन घटना को लागू करने की आवश्यकता है - दूसरे शब्दों में अगर RecyclerViewपुराने और नए संस्करण को पार करना चाहिए। यदि आपके पास मॉडल कक्षाएं सही equals()और hashCode()कार्यान्वयन हैं, तो आप आमतौर पर इसे ऊपर की तरह लागू कर सकते हैं। यदि हम कक्षा में एक equals()और hashCode()कार्यान्वयन जोड़ते हैं तो ExampleModelइसे कुछ इस तरह देखना चाहिए:

public class ExampleModel implements SortedListAdapter.ViewModel {

    private final long mId;
    private final String mText;

    public ExampleModel(long id, String text) {
        mId = id;
        mText = text;
    }

    public long getId() {
        return mId;
    }

    public String getText() {
        return mText;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        ExampleModel model = (ExampleModel) o;

        if (mId != model.mId) return false;
        return mText != null ? mText.equals(model.mText) : model.mText == null;

    }

    @Override
    public int hashCode() {
        int result = (int) (mId ^ (mId >>> 32));
        result = 31 * result + (mText != null ? mText.hashCode() : 0);
        return result;
    }
}

त्वरित पक्ष नोट: अधिकांश IDE जैसे Android Studio, IntelliJ और Eclipse में एक बटन के प्रेस पर आपके लिए जेनरेट equals()और hashCode()कार्यान्वयन की कार्यक्षमता है ! इसलिए आपको उन्हें स्वयं लागू करने की आवश्यकता नहीं है। इंटरनेट पर देखें कि यह आपके IDE में कैसे काम करता है!

अब आइए एक नजर डालते हैं आखिरी विधि पर:

@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
    return item1.getId() == item2.getId();
}

यह SortedListजाँचने के लिए कि दो आइटम एक ही चीज़ को संदर्भित करते हैं, इस विधि का उपयोग करता है। सबसे सरल शब्दों में (यह बताए बिना कि यह कैसे SortedListकाम करता है) यह निर्धारित करने के लिए उपयोग किया जाता है कि क्या कोई वस्तु पहले से ही मौजूद है Listऔर यदि ऐड, मूव या चेंज एनीमेशन को प्ले करने की आवश्यकता है। यदि आपके मॉडलों में एक आईडी है तो आप आमतौर पर इस विधि में केवल आईडी की तुलना करेंगे। यदि उन्हें इसकी जांच करने के लिए किसी अन्य तरीके का पता लगाने की आवश्यकता नहीं है, लेकिन फिर भी आप इसे लागू करते हैं, यह आपके विशिष्ट ऐप पर निर्भर करता है। आमतौर पर सभी मॉडलों को एक आईडी देना सबसे सरल विकल्प है - उदाहरण के लिए प्राथमिक कुंजी क्षेत्र हो सकता है यदि आप किसी डेटाबेस से डेटा क्वेरी कर रहे हैं।

SortedList.Callbackसही तरीके से लागू किए जाने के साथ हम निम्न का एक उदाहरण बना सकते हैं SortedList:

final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);

आप के निर्माता में पहले पैरामीटर के रूप SortedListमें अपने मॉडल के वर्ग को पास करने की आवश्यकता है। अन्य पैरामीटर बस SortedList.Callbackहम ऊपर परिभाषित है।

अगर हम लागू: अब के व्यापार करने के लिए नीचे जाओ Adapterएक साथ SortedListयह कुछ इस तरह दिखना चाहिए:

public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {

    private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
        @Override
        public int compare(ExampleModel a, ExampleModel b) {
            return mComparator.compare(a, b);
        }

        @Override
        public void onInserted(int position, int count) {
            notifyItemRangeInserted(position, count);
        }

        @Override
        public void onRemoved(int position, int count) {
            notifyItemRangeRemoved(position, count);
        }

        @Override
        public void onMoved(int fromPosition, int toPosition) {
            notifyItemMoved(fromPosition, toPosition);
        }

        @Override
        public void onChanged(int position, int count) {
            notifyItemRangeChanged(position, count);
        }

        @Override
        public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
            return oldItem.equals(newItem);
        }

        @Override
        public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
            return item1.getId() == item2.getId();
        }
    });

    private final LayoutInflater mInflater;
    private final Comparator<ExampleModel> mComparator;

    public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
        mInflater = LayoutInflater.from(context);
        mComparator = comparator;
    }

    @Override
    public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
        return new ExampleViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ExampleViewHolder holder, int position) {
        final ExampleModel model = mSortedList.get(position);
        holder.bind(model);
    }

    @Override
    public int getItemCount() {
        return mSortedList.size();
    }
}

Comparatorसॉर्ट करने के लिए तो हम एक ही उपयोग कर सकते हैं आइटम निर्माता के माध्यम से में पारित हो जाता है के लिए इस्तेमाल किया Adapterभी आइटम भिन्न क्रम में प्रदर्शित करने के लिए की अपेक्षा की जाती है।

अब हम लगभग हो चुके हैं! लेकिन हमें सबसे पहले वस्तुओं को जोड़ने या हटाने का तरीका चाहिए Adapter। इस उद्देश्य के लिए हम उन विधियों को जोड़ सकते हैं Adapterजिनसे हमें आइटम जोड़ने और हटाने की अनुमति मिलती है SortedList:

public void add(ExampleModel model) {
    mSortedList.add(model);
}

public void remove(ExampleModel model) {
    mSortedList.remove(model);
}

public void add(List<ExampleModel> models) {
    mSortedList.addAll(models);
}

public void remove(List<ExampleModel> models) {
    mSortedList.beginBatchedUpdates();
    for (ExampleModel model : models) {
        mSortedList.remove(model);
    }
    mSortedList.endBatchedUpdates();
}

हमें यहां किसी भी अधिसूचित तरीके को कॉल करने की आवश्यकता नहीं है क्योंकि SortedListपहले से ही इसके माध्यम से किया जाता है SortedList.Callback! इसके अलावा, इन विधियों का कार्यान्वयन एक अपवाद के साथ बहुत सीधा है: हटाने का तरीका जो एक Listमॉडल को निकालता है । चूंकि SortedListकेवल एक हटाने की विधि है जो एक एकल ऑब्जेक्ट को हटा सकती है जिसे हमें सूची पर लूप करने की आवश्यकता है और एक-एक करके मॉडल को हटा दें। beginBatchedUpdates()शुरुआत में कॉल करना उन सभी परिवर्तनों को दर्शाता है जो हम SortedListएक साथ करने जा रहे हैं और प्रदर्शन में सुधार करते हैं। जब हम कॉल endBatchedUpdates()करते हैं RecyclerViewतो एक ही बार में सभी परिवर्तनों के बारे में सूचित किया जाता है।

इसके अतिरिक्त आपको जो समझना है, वह यह है कि यदि आप इसमें कोई ऑब्जेक्ट जोड़ते हैं SortedListऔर यह पहले से ही है तो SortedListइसे दोबारा नहीं जोड़ा जाएगा। इसके बजाय विधि SortedListका उपयोग करता है यह areContentsTheSame()पता लगाने के लिए कि क्या वस्तु बदल गई है - और यदि इसमें RecyclerViewवसीयत में आइटम अपडेट है।

वैसे भी, जो मैं आमतौर पर पसंद करता हूं वह एक तरीका है जो मुझे RecyclerViewएक ही बार में सभी वस्तुओं को बदलने की अनुमति देता है । जो कुछ भी नहीं है उसे निकालें Listऔर उन सभी वस्तुओं को जोड़ें जो गायब हैं SortedList:

public void replaceAll(List<ExampleModel> models) {
    mSortedList.beginBatchedUpdates();
    for (int i = mSortedList.size() - 1; i >= 0; i--) {
        final ExampleModel model = mSortedList.get(i);
        if (!models.contains(model)) {
            mSortedList.remove(model);
        }
    }
    mSortedList.addAll(models);
    mSortedList.endBatchedUpdates();
}

यह विधि फिर से प्रदर्शन को बढ़ाने के लिए सभी अपडेट को एक साथ बैचती है। पहला लूप उल्टा है क्योंकि शुरू में एक आइटम को हटाने से उसके बाद आने वाली सभी वस्तुओं के सूचकांक में गड़बड़ हो जाती है और इससे डेटा असंगति जैसी समस्याओं के कुछ उदाहरण हो सकते हैं। उसके बाद हम केवल उन सभी वस्तुओं को जोड़ने के Listलिए SortedListउपयोग addAll()करने के लिए जोड़ते हैं जो पहले से ही नहीं हैं SortedListऔर - जैसे मैंने ऊपर वर्णित किया है - उन सभी वस्तुओं को अपडेट करें जो पहले से ही SortedListबदल चुके हैं लेकिन बदल गए हैं।

और इसके साथ Adapterही पूरा हो गया है। पूरी बात कुछ इस तरह दिखनी चाहिए:

public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {

    private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
        @Override
        public int compare(ExampleModel a, ExampleModel b) {
            return mComparator.compare(a, b);
        }

        @Override
        public void onInserted(int position, int count) {
            notifyItemRangeInserted(position, count);
        }

        @Override
        public void onRemoved(int position, int count) {
            notifyItemRangeRemoved(position, count);
        }

        @Override
        public void onMoved(int fromPosition, int toPosition) {
            notifyItemMoved(fromPosition, toPosition);
        }

        @Override
        public void onChanged(int position, int count) {
            notifyItemRangeChanged(position, count);
        }

        @Override
        public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
            return oldItem.equals(newItem);
        }

        @Override
        public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
            return item1 == item2;
        }
    });

    private final Comparator<ExampleModel> mComparator;
    private final LayoutInflater mInflater;

    public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
        mInflater = LayoutInflater.from(context);
        mComparator = comparator;
    }

    @Override
    public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final ItemExampleBinding binding = ItemExampleBinding.inflate(mInflater, parent, false);
        return new ExampleViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ExampleViewHolder holder, int position) {
        final ExampleModel model = mSortedList.get(position);
        holder.bind(model);
    }

    public void add(ExampleModel model) {
        mSortedList.add(model);
    }

    public void remove(ExampleModel model) {
        mSortedList.remove(model);
    }

    public void add(List<ExampleModel> models) {
        mSortedList.addAll(models);
    }

    public void remove(List<ExampleModel> models) {
        mSortedList.beginBatchedUpdates();
        for (ExampleModel model : models) {
            mSortedList.remove(model);
        }
        mSortedList.endBatchedUpdates();
    }

    public void replaceAll(List<ExampleModel> models) {
        mSortedList.beginBatchedUpdates();
        for (int i = mSortedList.size() - 1; i >= 0; i--) {
            final ExampleModel model = mSortedList.get(i);
            if (!models.contains(model)) {
                mSortedList.remove(model);
            }
        }
        mSortedList.addAll(models);
        mSortedList.endBatchedUpdates();
    }

    @Override
    public int getItemCount() {
        return mSortedList.size();
    }
}

फ़िल्टरिंग को लागू करने के लिए अब केवल एक चीज गायब है!


फ़िल्टर तर्क को लागू करना

फ़िल्टर तर्क को लागू करने के लिए हमें सबसे पहले Listसभी संभावित मॉडल को परिभाषित करना होगा । इस उदाहरण के लिए मैं एक बनाने Listकी ExampleModelफिल्मों की एक सरणी से उदाहरणों:

private static final String[] MOVIES = new String[]{
        ...
};

private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
    @Override
    public int compare(ExampleModel a, ExampleModel b) {
        return a.getText().compareTo(b.getText());
    }
};

private ExampleAdapter mAdapter;
private List<ExampleModel> mModels;
private RecyclerView mRecyclerView;

    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

    mAdapter = new ExampleAdapter(this, ALPHABETICAL_COMPARATOR);

    mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
    mBinding.recyclerView.setAdapter(mAdapter);

    mModels = new ArrayList<>();
    for (String movie : MOVIES) {
        mModels.add(new ExampleModel(movie));
    }
    mAdapter.add(mModels);
}

यहां कुछ खास नहीं चल रहा है, हम बस Adapterइसे इंस्टेंट करते हैं और इसे सेट करते हैं RecyclerView। उसके बाद हम ऐरे Listमें मूवी के नामों से मॉडल बनाते हैं MOVIES। फिर हम सभी मॉडलों को मॉडल में जोड़ते हैं SortedList

अब हम वापस जा सकते हैं, onQueryTextChange()जिसे हमने पहले परिभाषित किया था और फ़िल्टर तर्क को लागू करना शुरू किया था:

@Override
public boolean onQueryTextChange(String query) {
    final List<ExampleModel> filteredModelList = filter(mModels, query);
    mAdapter.replaceAll(filteredModelList);
    mBinding.recyclerView.scrollToPosition(0);
    return true;
}

यह फिर से बहुत सीधे आगे है। हम विधि कॉल filter()और पास Listके ExampleModelसाथ ही क्वेरी स्ट्रिंग के रूप में। फिर हम कॉल replaceAll()करते हैं Adapterऔर फ़िल्टर किए Listगए में पास करते हैं filter()। हम यह भी कॉल कर सकते हैं scrollToPosition(0)पर RecyclerViewयह सुनिश्चित करें कि उपयोगकर्ता हमेशा सभी आइटम देख सकते हैं जब किसी चीज़ को खोजने। अन्यथा RecyclerViewफ़िल्टर करते समय नीचे स्क्रॉल की गई स्थिति में रह सकते हैं और बाद में कुछ आइटम छिपा सकते हैं। खोज करते समय शीर्ष पर स्क्रॉल करना बेहतर उपयोगकर्ता अनुभव सुनिश्चित करता है।

अब केवल एक ही चीज शेष filter()है:

private static List<ExampleModel> filter(List<ExampleModel> models, String query) {
    final String lowerCaseQuery = query.toLowerCase();

    final List<ExampleModel> filteredModelList = new ArrayList<>();
    for (ExampleModel model : models) {
        final String text = model.getText().toLowerCase();
        if (text.contains(lowerCaseQuery)) {
            filteredModelList.add(model);
        }
    }
    return filteredModelList;
}

पहली चीज जो हम यहां करते हैं वह toLowerCase()क्वेरी स्ट्रिंग पर कॉल है । हम नहीं चाहते हैं कि हमारा खोज कार्य संवेदनशील हो और toLowerCase()हम सभी तुलनाओं पर कॉल करके यह सुनिश्चित कर सकें कि हम मामले की परवाह किए बिना समान परिणाम लौटा सकें। यह तब होता है जब Listहम इसमें पारित सभी मॉडलों के माध्यम से पुनरावृत्त होते हैं और यह जांचते हैं कि क्या क्वेरी स्ट्रिंग मॉडल के पाठ में निहित है। यदि यह है तो मॉडल को फ़िल्टर्ड में जोड़ा जाता है List

और बस! उपरोक्त कोड एपीआई स्तर 7 और इसके बाद के संस्करण पर चलेंगे और एपीआई स्तर 11 से शुरू होकर आपको मुफ्त में आइटम एनिमेशन मिलेंगे!

मुझे पता है कि यह एक बहुत ही विस्तृत विवरण है जो संभवतः इस पूरी चीज़ को वास्तव में की तुलना में अधिक जटिल लगता है, लेकिन एक तरीका है जिससे हम इस पूरी समस्या का सामान्यीकरण कर सकते हैं और बहुत सरलता के Adapterआधार पर इसे लागू कर सकते हैं SortedList


समस्या को सामान्य करना और एडेप्टर को सरल बनाना

इस खंड में मैं बहुत विस्तार में नहीं जा रहा हूं - आंशिक रूप से क्योंकि मैं स्टैक ओवरफ्लो पर जवाब के लिए वर्ण सीमा के खिलाफ चल रहा हूं, लेकिन यह भी क्योंकि इसमें से अधिकांश पहले ही ऊपर बताए गए हैं - लेकिन परिवर्तनों को संक्षेप में बताने के लिए: हम एक बेस Adapterक्लास लागू कर सकते हैं जो पहले से ही उदाहरणों के SortedListसाथ-साथ बाध्यकारी मॉडल से निपटने का ख्याल रखता है ViewHolderऔर एक के Adapterआधार पर लागू करने के लिए एक सुविधाजनक तरीका प्रदान करता हैSortedList । उसके लिए हमें दो काम करने होंगे:

  • हमें एक बनाने की जरूरत है ViewModel इंटरफ़ेस जिसे सभी मॉडल वर्गों को लागू करना होगा
  • हमें एक ViewHolderउपवर्ग बनाने की आवश्यकता है जो एक bind()विधि को परिभाषित करता है जो Adapterमॉडल को स्वचालित रूप से बांधने के लिए उपयोग कर सकता है।

यह हमें केवल उस सामग्री पर ध्यान केंद्रित करने की अनुमति देता है RecyclerViewजिसे केवल मॉडलों को लागू करने के द्वारा प्रदर्शित किया जाता है और इसके अनुरूप ViewHolderकार्यान्वयन होता है। इस बेस क्लास का उपयोग करके हमें Adapterइसके और इसके जटिल विवरण के बारे में चिंता करने की आवश्यकता नहीं है SortedList

SortedListAdapter

StackOverflow पर उत्तरों की वर्ण सीमा के कारण मैं इस बेस क्लास को लागू करने के प्रत्येक चरण के माध्यम से नहीं जा सकता या यहाँ पूर्ण स्रोत कोड भी जोड़ सकता हूँ, लेकिन आप इस बेस क्लास का पूर्ण स्रोत कोड पा सकते हैं - मैंने इसे कॉल किया SortedListAdapter- इसमें गिटहब गिस्ट

आपके जीवन को सरल बनाने के लिए मैंने jCenter पर एक पुस्तकालय प्रकाशित किया है जिसमें सम्‍मिलित है SortedListAdapter! यदि आप इसका उपयोग करना चाहते हैं तो आपको बस इतना करना है कि इस निर्भरता को अपने ऐप की बिल्ड.ग्रेड फ़ाइल में जोड़ें:

compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.1'

आप इस पुस्तकालय के बारे में अधिक जानकारी पुस्तकालय के मुखपृष्ठ पर पा सकते हैं ।

SortedListAdapter का उपयोग करना

उपयोग करने के लिए SortedListAdapterहमें दो बदलाव करने होंगे:

  • बदलो ViewHolderताकि यह विस्तारित हो SortedListAdapter.ViewHolder। प्रकार का पैरामीटर मॉडल होना चाहिए जो ViewHolderइस मामले में बाध्य होना चाहिए - इस मामले में ExampleModel। आपको performBind()इसके बजाय अपने मॉडल में डेटा को बांधना होगा bind()

    public class ExampleViewHolder extends SortedListAdapter.ViewHolder<ExampleModel> {
    
        private final ItemExampleBinding mBinding;
    
        public ExampleViewHolder(ItemExampleBinding binding) {
            super(binding.getRoot());
            mBinding = binding;
        }
    
        @Override
        protected void performBind(ExampleModel item) {
            mBinding.setModel(item);
        }
    }
  • सुनिश्चित करें कि आपके सभी मॉडल ViewModelइंटरफ़ेस को लागू करते हैं :

    public class ExampleModel implements SortedListAdapter.ViewModel {
        ...
    }

उसके बाद हमें केवल उन चीजों ExampleAdapterको बढ़ाने SortedListAdapterऔर हटाने के लिए अपडेट करना होगा जिनकी हमें अब आवश्यकता नहीं है। प्रकार पैरामीटर उस मॉडल का प्रकार होना चाहिए जिसके साथ आप काम कर रहे हैं - इस मामले में ExampleModel। लेकिन अगर आप विभिन्न प्रकार के मॉडल के साथ काम कर रहे हैं तो टाइप पैरामीटर को सेट करें ViewModel

public class ExampleAdapter extends SortedListAdapter<ExampleModel> {

    public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
        super(context, ExampleModel.class, comparator);
    }

    @Override
    protected ViewHolder<? extends ExampleModel> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
        final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
        return new ExampleViewHolder(binding);
    }

    @Override
    protected boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
        return item1.getId() == item2.getId();
    }

    @Override
    protected boolean areItemContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
        return oldItem.equals(newItem);
    }
}

उसके बाद हम कर रहे हैं! हालाँकि एक अंतिम बात जो उल्लेखित है: हमारे मूल SortedListAdapterमें वही add(), remove()या replaceAll()विधियाँ नहीं हैं ExampleAdapter। यह Editorसूची में आइटम को संशोधित करने के लिए एक अलग ऑब्जेक्ट का उपयोग करता है जिसे edit()विधि के माध्यम से एक्सेस किया जा सकता है । इसलिए यदि आप उन वस्तुओं को हटाना या जोड़ना चाहते हैं जिन्हें आपको कॉल करना है, edit()तो इस Editorउदाहरण पर आइटम जोड़ें और निकालें और एक बार जब आप कर लें, तो इस commit()पर कॉल करें SortedList: परिवर्तन लागू करने के लिए :

mAdapter.edit()
        .remove(modelToRemove)
        .add(listOfModelsToAdd)
        .commit();

इस तरह से किए जाने वाले सभी परिवर्तनों को प्रदर्शन बढ़ाने के लिए एक साथ बैच दिया जाता है। replaceAll()ऊपर दिए गए अध्यायों में हमने जो विधि लागू की है वह इस Editorवस्तु पर भी मौजूद है :

mAdapter.edit()
        .replaceAll(mModels)
        .commit();

अगर आप कॉल करना भूल जाते हैं commit()तो आपका कोई भी बदलाव लागू नहीं होगा!


4
@TiagoOliveira खैर यह सिर्फ बॉक्स से बाहर काम करने के लिए बनाया गया है: डी डेटा बाइंडिंग अपरिचित लोगों के लिए बाधा है, लेकिन मैंने इसे वैसे भी शामिल किया क्योंकि यह अद्भुत है और मैं इसे बढ़ावा देना चाहता हूं। किसी कारण से बहुत से लोगों को इसके बारे में पता नहीं लगता ...
Xaver Kapeller

78
मैंने अभी तक पूरा उत्तर नहीं पढ़ा है, मुझे इस टिप्पणी को लिखने के लिए अपना पढ़ना कहीं आधा करना पड़ा - यह सबसे अच्छा उत्तर है जो मुझे यहाँ एसओ पर मिला है! धन्यवाद!
daneejela

16
मुझे बस इतना पसंद है कि आप कैसे हैं: "यह आपके प्रश्न से स्पष्ट नहीं है कि आप किस समस्या से परेशान हैं, इसलिए यहां एक पूर्ण उदाहरण मैंने अभी किया है": D
फ्रेड

7
+1 केवल हमें यह दिखाने के लिए कि एंड्रॉइड में डेटा बाइंडिंग मौजूद है! मैंने इसके बारे में कभी नहीं सुना है और लगता है कि मैं इसका इस्तेमाल करना शुरू कर दूंगा। धन्यवाद
जॉर्ज Casariego

6
यह समाधान हास्यास्पद रूप से लंबा और आम तौर पर अति-इंजीनियर बोल रहा है। दूसरे के लिए जाओ।
एनरिको कासिनी

194

तुम सब करने की ज़रूरत को जोड़ने के लिए है filterमें विधि RecyclerView.Adapter:

public void filter(String text) {
    items.clear();
    if(text.isEmpty()){
        items.addAll(itemsCopy);
    } else{
        text = text.toLowerCase();
        for(PhoneBookItem item: itemsCopy){
            if(item.name.toLowerCase().contains(text) || item.phone.toLowerCase().contains(text)){
                items.add(item);
            }
        }
    }
    notifyDataSetChanged();
}

itemsCopyएडेप्टर के निर्माता में आरंभीकृत है जैसे itemsCopy.addAll(items)

यदि आप ऐसा करते हैं, तो बस फोन filterसे OnQueryTextListener:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        adapter.filter(query);
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        adapter.filter(newText);
        return true;
    }
});

यह मेरे फोनबुक को नाम और फोन नंबर को फ़िल्टर करने से एक उदाहरण है।


11
मुझे लगता है कि यह स्वीकृत उत्तर होना चाहिए। यह सरल है और यह सिर्फ काम करता है
जोस_जीडी

6
सरल और कुशल!
AlxDroidDev

11
ध्यान दें कि आप एनीमेशन खो देते हैं यदि आप @Xaver कपेलर उत्तर के बजाय इस दृष्टिकोण का पालन करते हैं।
विस्मित

23
स्वीकृत उत्तर का प्रयास न करें क्योंकि यह बहुत लंबा रास्ता है। यह जवाब काम करता है और लागू करने में आसान है। अपने मेनू मेनू XML पर "app: actionViewClass =" android.support.v7.widget.SearchView "जोड़ना न भूलें।
सजीथ

3
वास्तव में आइटम और आइटम यहां क्या है?
लकी_गर्ल

82

क्लीनर के रूप में @ श्रुति कमोजी के बाद, हम सिर्फ एक फिल्टर करने योग्य उपयोग कर सकते हैं, इसके लिए इसका मतलब है:

public abstract class GenericRecycleAdapter<E> extends RecyclerView.Adapter implements Filterable
{
    protected List<E> list;
    protected List<E> originalList;
    protected Context context;

    public GenericRecycleAdapter(Context context,
    List<E> list)
    {
        this.originalList = list;
        this.list = list;
        this.context = context;
    }

    ...

    @Override
    public Filter getFilter() {
        return new Filter() {
            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                list = (List<E>) results.values;
                notifyDataSetChanged();
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                List<E> filteredResults = null;
                if (constraint.length() == 0) {
                    filteredResults = originalList;
                } else {
                    filteredResults = getFilteredResults(constraint.toString().toLowerCase());
                }

                FilterResults results = new FilterResults();
                results.values = filteredResults;

                return results;
            }
        };
    }

    protected List<E> getFilteredResults(String constraint) {
        List<E> results = new ArrayList<>();

        for (E item : originalList) {
            if (item.getName().toLowerCase().contains(constraint)) {
                results.add(item);
            }
        }
        return results;
    }
} 

E यहाँ एक सामान्य प्रकार है, आप इसे अपनी कक्षा का उपयोग करके बढ़ा सकते हैं:

public class customerAdapter extends GenericRecycleAdapter<CustomerModel>

या ई को अपने इच्छित प्रकार में बदलें (<CustomerModel> उदाहरण के लिए)

फिर searchView से (विजेट आप menu.xml पर डाल सकते हैं):

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String text) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String text) {
        yourAdapter.getFilter().filter(text);
        return true;
    }
});

मैं कुछ इस तरह का उपयोग करें! ठीक और सामान्य नमूना काम करता है!
मेटुस

हैलो, जो मुझे इस के साथ कदम-वाई-चरण में मदद कर सकता है: stackoverflow.com/questions/40754174/…
Thorvald Olavsen

सबसे साफ जवाब!
आदालपारि

4
यह अप वोट किए गए उत्तर से बहुत बेहतर है क्योंकि ऑपरेशन परफॉर्मिंग विधि में एक कार्यकर्ता थ्रेड पर किया जाता है।
हम्म

1
लेकिन आप उसी सूची के संदर्भ को अलग-अलग चर में निर्दिष्ट करते हैं। उदाहरण के लिए इस .orinalList = सूची; आपको AddAll का उपयोग करना चाहिए या ArrayList कंस्ट्रक्टर में सूची पास करनी चाहिए
Florian Walther

5

बस एडाप्टर एक orignal और एक अस्थायी और औजार फिल्टर में दो सूची बनाएँ ।

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                final FilterResults oReturn = new FilterResults();
                final ArrayList<T> results = new ArrayList<>();
                if (origList == null)
                    origList = new ArrayList<>(itemList);
                if (constraint != null && constraint.length() > 0) {
                    if (origList != null && origList.size() > 0) {
                        for (final T cd : origList) {
                            if (cd.getAttributeToSearch().toLowerCase()
                                    .contains(constraint.toString().toLowerCase()))
                                results.add(cd);
                        }
                    }
                    oReturn.values = results;
                    oReturn.count = results.size();//newly Aded by ZA
                } else {
                    oReturn.values = origList;
                    oReturn.count = origList.size();//newly added by ZA
                }
                return oReturn;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(final CharSequence constraint,
                                          FilterResults results) {
                itemList = new ArrayList<>((ArrayList<T>) results.values);
                // FIXME: 8/16/2017 implement Comparable with sort below
                ///Collections.sort(itemList);
                notifyDataSetChanged();
            }
        };
    }

कहाँ पे

public GenericBaseAdapter(Context mContext, List<T> itemList) {
        this.mContext = mContext;
        this.itemList = itemList;
        this.origList = itemList;
    }

अच्छा समाधान है। मैंने दो सूचियाँ बनाईं और एक साधारण फ़िल्टर विधि का उपयोग किया। मैं अगली गतिविधि के लिए किसी आइटम के लिए सही एडेप्टर स्थिति पास नहीं कर सकता। मैं इस एक के लिए आपके द्वारा
AJW

4

एडाप्टर में:

public void setFilter(List<Channel> newList){
        mChannels = new ArrayList<>();
        mChannels.addAll(newList);
        notifyDataSetChanged();
    }

गतिविधि में:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                newText = newText.toLowerCase();
                ArrayList<Channel> newList = new ArrayList<>();
                for (Channel channel: channels){
                    String channelName = channel.getmChannelName().toLowerCase();
                    if (channelName.contains(newText)){
                        newList.add(channel);
                    }
                }
                mAdapter.setFilter(newList);
                return true;
            }
        });

3

साथ एंड्रॉयड वास्तुकला अवयव के उपयोग के माध्यम LiveData यह आसानी से किसी भी प्रकार के साथ लागू किया जा सकता एडाप्टर । आपको बस निम्नलिखित चरण करने होंगे:

1. से लौटने के लिए अपना डेटा सेटअप करें कमरे का डाटाबेस के रूप में LiveData नीचे उदाहरण में है:

@Dao
public interface CustomDAO{

@Query("SELECT * FROM words_table WHERE column LIKE :searchquery")
    public LiveData<List<Word>> searchFor(String searchquery);
}

2। अपने डेटा को एक विधि के माध्यम से लाइव अपडेट करने के लिए एक ViewModel ऑब्जेक्ट बनाएं जो आपके DAO और आपके UI को कनेक्ट करेगा

public class CustomViewModel extends AndroidViewModel {

    private final AppDatabase mAppDatabase;

    public WordListViewModel(@NonNull Application application) {
        super(application);
        this.mAppDatabase = AppDatabase.getInstance(application.getApplicationContext());
    }

    public LiveData<List<Word>> searchQuery(String query) {
        return mAppDatabase.mWordDAO().searchFor(query);
    }

}

3. ViewModel से अपना डेटा कॉल करें नीचे दिए गए के रूप में onQueryTextListener के माध्यम से क्वेरी में पारित करके फ्लाई पर :

अंदर onCreateOptionsMenuअपने श्रोता को निम्नानुसार सेट करें

searchView.setOnQueryTextListener(onQueryTextListener);

अपने क्वेरी श्रोता को अपने SearchActivity वर्ग में कहीं निम्नानुसार सेट करें

private android.support.v7.widget.SearchView.OnQueryTextListener onQueryTextListener =
            new android.support.v7.widget.SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    getResults(query);
                    return true;
                }

                @Override
                public boolean onQueryTextChange(String newText) {
                    getResults(newText);
                    return true;
                }

                private void getResults(String newText) {
                    String queryText = "%" + newText + "%";
                    mCustomViewModel.searchQuery(queryText).observe(
                            SearchResultsActivity.this, new Observer<List<Word>>() {
                                @Override
                                public void onChanged(@Nullable List<Word> words) {
                                    if (words == null) return;
                                    searchAdapter.submitList(words);
                                }
                            });
                }
            };

नोट : स्टेप्स (1.) और (2.) मानक एएसी व्यूमॉडल हैं और DAO कार्यान्वयन हैं, यहां चल रहा एकमात्र वास्तविक "मैजिक" OnQueryTextListener में है जो क्वेरी पाठ परिवर्तन के रूप में गतिशील रूप से आपकी सूची के परिणामों को अपडेट करेगा।

यदि आपको मामले पर अधिक स्पष्टीकरण की आवश्यकता है तो कृपया पूछने में संकोच न करें। मुझे उम्मीद है कि इससे मदद मिली :)।


1

यह फ़िल्टरिंग एनीमेशन को न खोने के लिए @klimat के उत्तर का विस्तार करने पर मेरा विचार है।

public void filter(String query){
    int completeListIndex = 0;
    int filteredListIndex = 0;
    while (completeListIndex < completeList.size()){
        Movie item = completeList.get(completeListIndex);
        if(item.getName().toLowerCase().contains(query)){
            if(filteredListIndex < filteredList.size()) {
                Movie filter = filteredList.get(filteredListIndex);
                if (!item.getName().equals(filter.getName())) {
                    filteredList.add(filteredListIndex, item);
                    notifyItemInserted(filteredListIndex);
                }
            }else{
                filteredList.add(filteredListIndex, item);
                notifyItemInserted(filteredListIndex);
            }
            filteredListIndex++;
        }
        else if(filteredListIndex < filteredList.size()){
            Movie filter = filteredList.get(filteredListIndex);
            if (item.getName().equals(filter.getName())) {
                filteredList.remove(filteredListIndex);
                notifyItemRemoved(filteredListIndex);
            }
        }
        completeListIndex++;
    }
}

मूल रूप से यह क्या करता है एक पूरी सूची के माध्यम से देख रहा है और एक फ़िल्टर की गई सूची में आइटम को एक-एक करके जोड़ / निकाल रहा है।


0

मैं अनुशंसा करता हूं कि आप खोज की गई पाठ को साफ़ करने के बाद नीचे दिए गए 2 चीज़ों के साथ @Xaver Kapeller के समाधान को संशोधित करें (एडॉप्टर की फ़िल्टर बैक अब काम नहीं करती है) एडॉप्टर की सूची के कारण फ़िल्टर सूची की तुलना में छोटा आकार है और IndexOutOfBoundsEception हुई है। इसलिए कोड को नीचे के रूप में संशोधित करना होगा

public void addItem(int position, ExampleModel model) {
    if(position >= mModel.size()) {
        mModel.add(model);
        notifyItemInserted(mModel.size()-1);
    } else {
        mModels.add(position, model);
        notifyItemInserted(position);
    }
}

और MoveItem कार्यक्षमता में भी संशोधन करें

public void moveItem(int fromPosition, int toPosition) {
    final ExampleModel model = mModels.remove(fromPosition);
    if(toPosition >= mModels.size()) {
        mModels.add(model);
        notifyItemMoved(fromPosition, mModels.size()-1);
    } else {
        mModels.add(toPosition, model);
        notifyItemMoved(fromPosition, toPosition); 
    }
}

आशा है कि यह आपकी मदद कर सकता है!


यह बिल्कुल जरूरी नहीं है।
Xaver Kapeller

मूल उत्तर के लिए यदि आप ऐसा नहीं करते हैं कि IndexOutOfBoundsException हो जाएगा, तो क्यों आवश्यक नहीं है ???? क्या आप एक लॉग चाहते हैं? @XaverKapeller
toidv

कोई अपवाद केवल तब नहीं होगा जब आप Adapterगलत तरीके से लागू कर रहे हैं । आपके कोड को देखे बिना मुझे लगता है कि सबसे संभावित समस्या यह है कि आप सभी मदों के साथ सूची की एक प्रति नहीं दे रहे हैं Adapter
Xaver कपेलर

त्रुटि लॉग: W / System.err: java.lang.IndexOutOfBoundsException: अमान्य सूचकांक 36, आकार 35 W / System.err है: java.util.ArrayList.throwIthexOutOfBoundsException (ArrayList.java:255) W / System.err पर। at java.util.ArrayList.add (ArrayList.java:147) W / System.err: com.quomodo.inploi.ui.adapter पर उपलब्ध है। MultipleSelectFilterAdapter.addItem (MultipleSelectFilterAdapter.java:125) W / System.err .quomodo.inploi.ui.adapter.ultipleSelectFilterAdapter.applyAndAnimateAdditions (MultipleSelectFilterAdapter.java:78)
toidio

कृपया नीचे दिए गए स्रोत कोड को देखने में मदद करने के लिए @XaverKapeller gist.github.com/toidv/fe71dc45169e4138271b52fdb29420c5
toidv

0

खोज और क्लिकलिस्टर के साथ Recyclerview

अपने एडेप्टर में एक इंटरफ़ेस जोड़ें।

public interface SelectedUser{

    void selectedUser(UserModel userModel);

}

अपनी मुख्यता में इंटरफ़ेस लागू करें और विधि को ओवरराइड करें। @Override सार्वजनिक शून्य चयनित उपयोगकर्ता (UserModel userModel) {

    startActivity(new Intent(MainActivity.this, SelectedUserActivity.class).putExtra("data",userModel));



}

पूर्ण ट्यूटोरियल और स्रोत कोड: खोज और onclicklistener के साथ Recyclerview


-1

मैंने इसमें कुछ संशोधनों के साथ लिंक का उपयोग करके उसी समस्या को हल किया है। कार्ड के साथ RecyclerView पर खोज फ़िल्टर। क्या यह भी संभव है?(उम्मीद है की यह मदद करेगा)।

यहाँ मेरा एडेप्टर क्लास है

public class ContactListRecyclerAdapter extends RecyclerView.Adapter<ContactListRecyclerAdapter.ContactViewHolder> implements Filterable {

Context mContext;
ArrayList<Contact> customerList;
ArrayList<Contact> parentCustomerList;


public ContactListRecyclerAdapter(Context context,ArrayList<Contact> customerList)
{
    this.mContext=context;
    this.customerList=customerList;
    if(customerList!=null)
    parentCustomerList=new ArrayList<>(customerList);
}

   // other overrided methods

@Override
public Filter getFilter() {
    return new FilterCustomerSearch(this,parentCustomerList);
}
}

// फ़िल्टर वर्ग

import android.widget.Filter;
import java.util.ArrayList;


public class FilterCustomerSearch extends Filter
{
private final ContactListRecyclerAdapter mAdapter;
ArrayList<Contact> contactList;
ArrayList<Contact> filteredList;

public FilterCustomerSearch(ContactListRecyclerAdapter mAdapter,ArrayList<Contact> contactList) {
    this.mAdapter = mAdapter;
    this.contactList=contactList;
    filteredList=new ArrayList<>();
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
    filteredList.clear();
    final FilterResults results = new FilterResults();

    if (constraint.length() == 0) {
        filteredList.addAll(contactList);
    } else {
        final String filterPattern = constraint.toString().toLowerCase().trim();

        for (final Contact contact : contactList) {
            if (contact.customerName.contains(constraint)) {
                filteredList.add(contact);
            }
            else if (contact.emailId.contains(constraint))
            {
                filteredList.add(contact);

            }
            else if(contact.phoneNumber.contains(constraint))
                filteredList.add(contact);
        }
    }
    results.values = filteredList;
    results.count = filteredList.size();
    return results;
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
    mAdapter.customerList.clear();
    mAdapter.customerList.addAll((ArrayList<Contact>) results.values);
    mAdapter.notifyDataSetChanged();
}

}

// गतिविधि वर्ग

public class HomeCrossFadeActivity extends AppCompatActivity implements View.OnClickListener,OnFragmentInteractionListener,OnTaskCompletedListner
{
Fragment fragment;
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_homecrossfadeslidingpane2);CardView mCard;
   setContentView(R.layout.your_main_xml);}
   //other overrided methods
  @Override
   public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.

    MenuInflater inflater = getMenuInflater();
    // Inflate menu to add items to action bar if it is present.
    inflater.inflate(R.menu.menu_customer_view_and_search, menu);
    // Associate searchable configuration with the SearchView
    SearchManager searchManager =
            (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView =
            (SearchView) menu.findItem(R.id.menu_search).getActionView();
    searchView.setQueryHint("Search Customer");
    searchView.setSearchableInfo(
            searchManager.getSearchableInfo(getComponentName()));

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            if(fragment instanceof CustomerDetailsViewWithModifyAndSearch)
                ((CustomerDetailsViewWithModifyAndSearch)fragment).adapter.getFilter().filter(newText);
            return false;
        }
    });



    return true;
}
}

OnQueryTextChangeListener () विधि में अपने एडाप्टर का उपयोग करें। मैंने इसे टुकड़े टुकड़े करने के लिए डाला है क्योंकि मेरा पालन टुकड़ा में है। आप एडॉप्टर का उपयोग सीधे कर सकते हैं यदि इसकी गतिविधि कक्षा में हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.