جستجو در RecyclerView


فیلتر جست و جو در RecyclerView

آموزش قدم به قدم ساخت امکان جستجو در RecyclerView

جستجو در RecyclerView امکانی ست که در برنامه های بسیاری به آن نیاز خواهیم داشت. در این آموزش از یک RecyclerView آماده استفاده می کنیم تا قدم به قدم  امکان جستجو در RecyclerView را پیاده سازی کنیم. اگر به نحوه پیاده سازی آداپتر و ساخت RecyclerView نیاز دارید می توانید از این لینک استفاده کنید.

RecyclerView مورد نظر لیست زیر را نمایش می دهد:

لیست RecyclerView آماده

و حالا بدون حرف اضافه ای به سراغ کد می رویم.

قدم 1 : اضافه کردن icon جستجو به toolbar

با راست کلیک روی پوشه res و ساختن یک دایرکتوری جدید مثل تصویر، دایرکتوری menu رو میسازیم:

ساخت منو برای افزودن جستجو

 

و در این دایرکتوری جدید یک resource file جدید، مثلا با نام main_menu میسازیم. و داخل آن  آیتمی با attributeهای زیر می سازیم:

<item android:id="@+id/action_search"
    android:title="Search"
    android:icon="@drawable/ic_search_black_24dp"
    app:showAsAction="always|collapseActionView"
    app:actionViewClass="androidx.appcompat.widget.SearchView"
    />

در این قطعه کد showAsAction نحوه نمایش search icon را مشخص می کند و خط آخر تعیین می کند که این آیتم از کدام کلاس تبعیت می کند.

 قدم 2: نمایش icon جستجو

به این منظور روی پوشه drawable راست کلیک کرده و در new با انتخاب گزینه vector asset می توان icon مربوط به جستجو را پیدا کرد و به پروژه افزود.

قدم 3 : ایجاد منو ساخته شده در MainActivity

در این مرحله متد () onCreateOptionsMenu را override می کنیم.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    return super.onCreateOptionsMenu(menu);
}

در خط اولی که به این متد اضافه می کنیم در واقع menu مورد نظر را به عنوان پارامتر ورودی از resources می گیریم و آن را توسط inflator می کشیم :

getMenuInflater().inflate(R.menu.main_manu,menu);

در واقع inflator مثل یک نقاش عمل می کند که یک layout را بعنوان ورودی گرفته و در جایی که می خواهیم آن را ترسیم می کند.

خط دوم ساختن یک آیتم از کلاس MenuItem و پیدا کردن آیتم در resource مورد نظر هست.

MenuItem item = menu.findItem(R.id.action_search);

حال باید SearchView را تعریف کنیم. اما دقت کنید باید همان کلاسی را انتخاب کنیم که هنگام تعریف آیتم از آن استفاده کردیم :

انتخاب کلاس مورد نظر SearchView

کلاس searchView

و در نهایت قطعه کد زیر برای تکمیل این مرحله در متد  () onCreateOptionsMenu:

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

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

 

search-in-recyclerview

همان طور که می بینید icon جستجو به درستی نمایش داده شد. با کلیک بر روی علامت جست وجو تبدیل به قسمتی برای سرچ کردن می شود و این رفتار به دلیل نوشتن قسمت دوم از این مورد هست که برای آیتم در نظر گرفتیم :

app:showAsAction="always|collapseActionView"

قدم 4 : پیاده سازی فیلترها در کلاس آداپتر recyclerView مربوطه

filterable-interface

filterable interface از کلاس android.widget متدی با نام ()getFilter دارد که برای ادامه این آموزش به پیاده سازی آن نیاز داریم.

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

هدف ما جستجو بین تمام عناوین موجود هست پس به یک لیست از نام آنها نیاز داریم. یک field جدید در recyclerView مربوطه می سازیم و در متد سازنده (constructor) آنرا مقدار دهی می کنیم.

private List<Movie> movieListAll;

public MovieAdapter(List<Movie> movieList) {
    this.movieList = movieList;
    this.movieListAll = new ArrayList<>(movieList);
}

در واقع ما برای دسترسی به تمامی عناوین پس از جستجو و محدود کردن آنها، یک فیلد کمکی تعریف کردیم که بتوانیم تمامی عناوین را در آن نگهداری کنیم. تا در صورت بستن جستجو هم چنان بتوانیم تمام عناوین را نمایش داده، یا جستجوی مجددی انجام دهیم.

قدم 5 : پیاده سازی متد ()getFilter

این متد باید به جای null یک شی از نوع Filter به ما برگرداند. با new کردن شی ای از این کلاس بلافاصه با دو متد رو به رو می شویم. وظیفه به دست آوردن نتیجه جستجو و نمایش نتیجه به عهده این دو تابع می باشد.

Filter filter = new Filter() {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        return null;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {

    }
};

توجه داشته باشید متد اول وظیفه دارد که نتیجه مشخصی را برای ما به دست آورد. این عمل می تواند زمان بر باشد، پس روی یک thread دیگر انجام خواهد شد(background thread).

و متد publishResult وظیفه نمایش نتایج را بر روی UI دارد پس کار خود را روی UI thread انجام خواهد داد.

و اما پیاده سازی متدها:

@Override
    protected FilterResults performFiltering(CharSequence constraint) {
        List<String> movies=new ArrayList<>();
        for(int i=0;i<movieListAll.size();i++){
            movies.add(movieListAll.get(i).getTitle());
        }

        List<String> filteredList = new ArrayList<>();
        if(constraint.toString().isEmpty()){
            filteredList.addAll(movies);
        }else{
            for(String movie:movies){
                if(movie.toLowerCase().contains(constraint.toString().toLowerCase())){
                    filteredList.add(movie);
                }
            }
        }
        FilterResults filterResults = new FilterResults();
        filterResults.values = filteredList;
        return filterResults;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        movieList.clear();
        movieList.addAll((Collection<? extends Movie>) results.values);
        notifyDataSetChanged();
    }
};

اما چه کردیم ؟ ؟ یک لیست از اسامی فیلم ها گرفتیم. ساده ترین حالت، حالتی ست که تابع هیچ ورودی ای نگیرد! پس چک کنیم. اگر خالی بود که همان لیست تمامی اسم ها(که بالاتر بعنوان یه فیلد ساختیم) رو بگیر و نمایش بده. در غیر این صورت به کمک foreach نتیجه مورد نظر را جستجو کن و برای نمایش آماده کن. در واقع نتیجه در یک object از جنس FilterResult قرار می گیرد.

همین شی به عنوان پارامتر ورودی به متد publishResult() پاس داده خواهد شد. نهایتا نتیجه به نوع کلاس movieList تبدیل(cast) خواهد شد.

چون در تعداد مواردی که recyclerView باید نمایش دهد تغییری ایجاد شده در آخر با صدا کردن متد ()notifyDataSetChanged این تغییر را به RecyclerView اطلاع می دهیم.

قدم 6: متد onQueryTextChanged  در MainActivity

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

و در نهایت با اجرای برنامه خروجی مورد نظر را مشاهده می کنیم :

نتیجه جست و جو در ریسایکلر ویو

دوست دارید در آموزش های بعدی صفر تا صد اندروید چه مواردی را داشته باشیم؟

به این پست امتیاز دهید

روی ستاره های کلیک کنید و امتیاز بدید

میانگین امتیاز / 5. تعداد:

4 دیدگاه در نوشته: “جستجو در RecyclerView

  1. drdvm گفت:

    سلام لطفا در مورد ذخیره ی تعداد کلیک بر روی کاردویو صحبت کمید چون من یک ریسایکلر دارم که بیشترین کلیک شده ها از یک ریسایکلر ویوی دیگه رو نشون میده . مثل بازار اندروید که یک ریسایکلر عادی داره برای اپ و یک ریسایکلر دیگه برای اپ های پر دانلود.

    1. نسیم نژند گفت:

      برای این کار لازمه تعداد کلیک ها جایی مثل یک دیتابیس یا sharedpreferences ذخیره بشه. اگه مثل کافه بازار باشه باید روی سروری ذخیره شه که برای همه نتیجه یکسانی رو نمایش بده. اما اگر یک مورد شخصی برای کاربر باشه از دیتابیس یا sharedpreferences استفاده می کنیم.

  2. محمد گفت:

    adapter در قدم ششم از کجا اومده؟

    1. نسیم نژند گفت:

      همون طور که در شروع مقاله ذکر شده، نحوه ساخت ریسایکلرویو در این مقاله مد نظر نیست. ساخت آداپتر اولین قدم برای ساخت recyclerView هست که میتونید در این مقاله مطالعه بفرمایید.
      https://gitigit.com/recyclerview-on-android/%20%E2%80%8E

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *




Enter Captcha Here : *

Reload Image