Cách lọc RecyclerView với SearchView


319

Tôi đang cố gắng thực hiện SearchViewtừ thư viện hỗ trợ. Tôi muốn người dùng sử dụng SearchViewđể lọc a Listphim trong a RecyclerView.

Tôi đã theo một vài hướng dẫn cho đến nay và tôi đã thêm SearchViewvào ActionBar, nhưng tôi không thực sự chắc chắn nơi để đi từ đây. Tôi đã thấy một vài ví dụ nhưng không ai trong số họ hiển thị kết quả khi bạn bắt đầu nhập.

Đây là của tôi 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);
    }
}

Và đây là 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);
        }
    }
}

Câu trả lời:


913

Giới thiệu

Vì nó không thực sự rõ ràng từ câu hỏi của bạn chính xác là bạn đang gặp vấn đề gì, tôi đã viết lên hướng dẫn nhanh này về cách triển khai tính năng này; nếu bạn vẫn còn thắc mắc hãy hỏi.

Tôi có một ví dụ hoạt động về tất cả mọi thứ tôi đang nói ở đây trong Kho lưu trữ GitHub này .
Nếu bạn muốn biết thêm về dự án ví dụ, hãy truy cập trang chủ của dự án .

Trong mọi trường hợp, kết quả sẽ trông giống như thế này:

hình ảnh demo

Nếu trước tiên bạn muốn chơi xung quanh với ứng dụng demo, bạn có thể cài đặt nó từ Cửa hàng Play:

Tải nó trên Google Play

Dù sao đi nữa, hãy bắt đầu.


Thiết lập SearchView

Trong thư mục res/menutạo một tập tin mới gọi là main_menu.xml. Trong đó thêm một mục và thiết lập actionViewClassđể android.support.v7.widget.SearchView. Vì bạn đang sử dụng thư viện hỗ trợ, bạn phải sử dụng không gian tên của thư viện hỗ trợ để đặt actionViewClassthuộc tính. Tệp xml của bạn sẽ trông giống như thế này:

<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>

Trong Fragmenthoặc Activitybạn phải tăng xml menu này như bình thường, sau đó bạn có thể tìm cái MenuItemchứa SearchViewvà thực hiện cái OnQueryTextListenermà chúng ta sẽ sử dụng để lắng nghe những thay đổi của văn bản được nhập vào 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;
}

Và bây giờ SearchViewđã sẵn sàng để được sử dụng. Chúng tôi sẽ triển khai logic bộ lọc sau này sau onQueryTextChange()khi hoàn thành việc triển khai Adapter.


Thiết lập Adapter

Đầu tiên và quan trọng nhất, đây là lớp mô hình mà tôi sẽ sử dụng cho ví dụ này:

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;
    }
}

Đây chỉ là mô hình cơ bản của bạn sẽ hiển thị một văn bản trong RecyclerView. Đây là bố cục tôi sẽ sử dụng để hiển thị văn bản:

<?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>

Như bạn thấy tôi sử dụng Data Binding. Nếu bạn chưa bao giờ làm việc với ràng buộc dữ liệu trước khi đừng nản lòng! Nó rất đơn giản và mạnh mẽ, tuy nhiên tôi không thể giải thích nó hoạt động như thế nào trong phạm vi của câu trả lời này.

Đây là ViewHolderđối với ExampleModellớp:

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);
    }
}

Lại không có gì đặc biệt. Nó chỉ sử dụng liên kết dữ liệu để liên kết lớp mô hình với bố cục này như chúng ta đã định nghĩa trong bố cục xml ở trên.

Bây giờ chúng ta cuối cùng cũng có thể đến phần thực sự thú vị: Viết Adaptor. Tôi sẽ bỏ qua việc thực hiện cơ bản Adaptervà thay vào đó sẽ tập trung vào các phần có liên quan đến câu trả lời này.

Nhưng trước tiên, có một điều chúng ta phải nói về: SortedListLớp học.


Danh sách được sắp xếp

Đây SortedListlà một công cụ hoàn toàn tuyệt vời là một phần của RecyclerViewthư viện. Nó quan tâm đến việc thông báo Adaptervề các thay đổi về tập dữ liệu và làm như vậy nó là một cách rất hiệu quả. Điều duy nhất nó yêu cầu bạn làm là chỉ định một thứ tự của các yếu tố. Bạn cần phải làm điều đó bằng cách thực hiện một compare()phương thức so sánh hai yếu tố SortedListgiống như a Comparator. Nhưng thay vì sắp xếp Listnó được sử dụng để sắp xếp các mục trong RecyclerView!

Các SortedListtương tác với Adapterthông qua một Callbacklớp mà bạn phải thực hiện:

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();
    }
}

Trong phương pháp ở trên cùng của callback như onMoved, onInsertedvv bạn phải gọi tương đương với phương pháp của bạn thông báo Adapter. Ba phương thức ở dưới cùng compare, areContentsTheSameareItemsTheSame bạn phải thực hiện theo những gì loại của các đối tượng bạn muốn hiển thị và theo thứ tự các đối tượng này sẽ xuất hiện trên màn hình.

Chúng ta hãy thực hiện từng phương pháp một:

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

Đây là compare()phương pháp tôi đã nói trước đó. Trong ví dụ này tôi chỉ chuyển cuộc gọi đến một Comparatorso sánh hai mô hình. Nếu bạn muốn các mục xuất hiện theo thứ tự bảng chữ cái trên màn hình. Bộ so sánh này có thể trông như thế này:

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

Bây giờ hãy xem phương pháp tiếp theo:

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

Mục đích của phương pháp này là xác định xem nội dung của một mô hình có thay đổi hay không. Việc SortedListsử dụng điều này để xác định xem một sự kiện thay đổi có cần phải được gọi hay không - nói cách khác là liệu có RecyclerViewnên vượt qua phiên bản cũ và mới hay không. Nếu bạn mô hình các lớp có một chính xác equals()hashCode()thực hiện, bạn thường có thể thực hiện nó như trên. Nếu chúng ta thêm một equals()hashCode()thực hiện vào ExampleModellớp, nó sẽ trông giống như thế này:

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;
    }
}

Lưu ý nhanh: Hầu hết các IDE như Android Studio, IntelliJ và Eclipse đều có chức năng tạo equals()hashCode()triển khai cho bạn chỉ bằng cách nhấn nút! Vì vậy, bạn không phải tự thực hiện chúng. Tra cứu trên internet cách thức hoạt động trong IDE của bạn!

Bây giờ chúng ta hãy xem phương pháp cuối cùng:

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

Việc SortedListsử dụng phương pháp này để kiểm tra nếu hai mục đề cập đến cùng một điều. Nói một cách đơn giản nhất (không giải thích cách thức SortedListhoạt động), điều này được sử dụng để xác định xem một đối tượng đã được chứa trongList và nếu cần thêm, di chuyển hoặc thay đổi hình ảnh động cần phải được phát. Nếu mô hình của bạn có id, bạn thường chỉ so sánh id trong phương thức này. Nếu họ không cần bạn phải tìm ra một số cách khác để kiểm tra điều này, nhưng cuối cùng bạn thực hiện điều này phụ thuộc vào ứng dụng cụ thể của bạn. Thông thường, đây là tùy chọn đơn giản nhất để cung cấp cho tất cả các mô hình id - ví dụ đó có thể là trường khóa chính nếu bạn đang truy vấn dữ liệu từ cơ sở dữ liệu.

Với việc SortedList.Callbackthực hiện chính xác, chúng ta có thể tạo một thể hiện của SortedList:

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

Là tham số đầu tiên trong hàm tạo của SortedListbạn cần vượt qua lớp mô hình của bạn. Các tham số khác chỉ là SortedList.Callbackchúng tôi xác định ở trên.

Bây giờ chúng ta hãy bắt tay vào kinh doanh: Nếu chúng ta thực hiện Adaptervới SortedListnó thì nó sẽ trông giống như thế này:

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();
    }
}

Việc Comparatorsử dụng để sắp xếp mục được truyền qua hàm tạo để chúng ta có thể sử dụng tương tự Adapterngay cả khi các mục được cho là được hiển thị theo thứ tự khác.

Bây giờ chúng ta gần như đã hoàn tất! Nhưng trước tiên chúng ta cần một cách để thêm hoặc xóa các mục vào Adapter. Với mục đích này, chúng tôi có thể thêm các phương thức vào Adapterđó cho phép chúng tôi thêm và xóa các mục vào 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();
}

Chúng tôi không cần phải gọi bất kỳ phương thức thông báo nào ở đây vì SortedListđã thực hiện điều này thông qua SortedList.Callback! Bên cạnh đó, việc thực hiện các phương thức này khá đơn giản với một ngoại lệ: phương thức remove loại bỏ một Listmô hình. Vì SortedListchỉ có một phương thức loại bỏ có thể loại bỏ một đối tượng duy nhất, chúng ta cần lặp qua danh sách và loại bỏ từng mô hình một. Gọi beginBatchedUpdates()vào các đợt đầu tiên tất cả các thay đổi chúng ta sẽ thực hiện SortedListcùng nhau và cải thiện hiệu suất. Khi chúng tôi gọi endBatchedUpdates()thì RecyclerViewđược thông báo về tất cả các thay đổi cùng một lúc.

Ngoài ra, điều bạn phải hiểu là nếu bạn thêm một đối tượng vào SortedListvà nó đã ở trong SortedListđó thì nó sẽ không được thêm lại. Thay vào đó, phương thức SortedListsử dụng areContentsTheSame()phương pháp để tìm hiểu xem đối tượng đã thay đổi chưa - và nếu nó có mục trong đó RecyclerViewsẽ được cập nhật.

Dù sao, những gì tôi thường thích là một phương pháp cho phép tôi thay thế tất cả các mục RecyclerViewcùng một lúc. Xóa mọi thứ không có trong Listvà thêm tất cả các mục bị thiếu trong 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();
}

Phương pháp này một lần nữa bó tất cả các bản cập nhật lại với nhau để tăng hiệu suất. Vòng lặp đầu tiên là ngược lại vì việc loại bỏ một mục khi bắt đầu sẽ làm rối loạn các chỉ mục của tất cả các mục xuất hiện sau nó và điều này có thể dẫn đến một số trường hợp gặp vấn đề như sự không nhất quán dữ liệu. Sau đó, chúng tôi chỉ cần thêm Listvào việc SortedListsử dụng addAll()để thêm tất cả các mục chưa có trong SortedListvà - giống như tôi đã mô tả ở trên - cập nhật tất cả các mục đã có trong SortedListnhưng đã thay đổi.

Và với điều đó Adapterlà hoàn thành. Toàn bộ mọi thứ sẽ trông giống như thế này:

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();
    }
}

Điều duy nhất còn thiếu bây giờ là thực hiện lọc!


Thực hiện logic bộ lọc

Để thực hiện logic bộ lọc, trước tiên chúng ta phải xác định một Listtrong tất cả các mô hình có thể. Ví dụ này tôi tạo ra một Listtrong ExampleModelcác trường hợp từ một loạt các phim:

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);
}

Không có gì đặc biệt xảy ra ở đây, chúng tôi chỉ cần khởi tạo Adaptervà đặt nó thành RecyclerView. Sau đó, chúng tôi tạo ra một Listmô hình từ các tên phim trong MOVIESmảng. Sau đó, chúng tôi thêm tất cả các mô hình vào SortedList.

Bây giờ chúng ta có thể quay lại onQueryTextChange()cái mà chúng ta đã xác định trước đó và bắt đầu triển khai logic bộ lọc:

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

Đây là một lần nữa khá thẳng về phía trước. Chúng tôi gọi phương thức filter()và vượt qua trong Listcác ExampleModels cũng như chuỗi truy vấn. Sau đó chúng tôi gọi replaceAll()vào Adaptervà vượt qua trong lọc Listđược trả về bởi filter(). Chúng tôi cũng phải gọi scrollToPosition(0)về RecyclerViewđể đảm bảo rằng người dùng luôn có thể xem tất cả các mục khi tìm kiếm một cái gì đó. Nếu không, RecyclerViewcó thể ở vị trí cuộn xuống trong khi lọc và sau đó ẩn một vài mục. Cuộn lên trên cùng đảm bảo trải nghiệm người dùng tốt hơn trong khi tìm kiếm.

Điều duy nhất còn lại phải làm bây giờ là filter()tự thực hiện :

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;
}

Điều đầu tiên chúng ta làm ở đây là gọi toLowerCase()trên chuỗi truy vấn. Chúng tôi không muốn chức năng tìm kiếm của chúng tôi phân biệt chữ hoa chữ thường và bằng cách gọi toLowerCase()tất cả các chuỗi chúng tôi so sánh, chúng tôi có thể đảm bảo rằng chúng tôi trả về cùng một kết quả bất kể trường hợp nào. Sau đó, nó chỉ lặp qua tất cả các mô hình trong Listchúng ta đã truyền vào nó và kiểm tra xem chuỗi truy vấn có được chứa trong văn bản của mô hình không. Nếu có thì mô hình được thêm vào bộ lọc List.

Và đó là nó! Đoạn mã trên sẽ chạy trên API cấp 7 trở lên và bắt đầu với API cấp 11, bạn sẽ có được hoạt hình vật phẩm miễn phí!

Tôi nhận ra rằng đây là một mô tả rất chi tiết có thể làm cho toàn bộ điều này có vẻ phức tạp hơn thực tế, nhưng có một cách chúng ta có thể khái quát toàn bộ vấn đề này và thực hiện Adapterdựa trên SortedListđơn giản hơn nhiều.


Tổng quát hóa vấn đề và đơn giản hóa Bộ điều hợp

Trong phần này tôi sẽ không đi sâu vào chi tiết - một phần vì tôi đang chạy ngược lại giới hạn ký tự cho các câu trả lời trên Stack Overflow mà còn bởi vì hầu hết đã được giải thích ở trên - nhưng để tóm tắt các thay đổi: Chúng tôi có thể triển khai một Adapterlớp cơ sở đã quan tâm đến việc xử lý các SortedListmô hình ràng buộc cũng như các ViewHoldertrường hợp và cung cấp một cách thuận tiện để thực hiện Adapterdựa trên một SortedList. Vì vậy, chúng ta phải làm hai việc:

  • Chúng ta cần tạo một ViewModelgiao diện mà tất cả các lớp mô hình phải thực hiện
  • Chúng ta cần tạo một ViewHolderlớp con xác định một bind()phương thức Adaptercó thể sử dụng để liên kết các mô hình tự động.

Điều này cho phép chúng tôi chỉ tập trung vào nội dung được cho là sẽ được hiển thị trong đó RecyclerViewbằng cách chỉ thực hiện các mô hình và có các ViewHoldertriển khai tương ứng . Sử dụng lớp cơ sở này, chúng tôi không phải lo lắng về các chi tiết phức tạp của AdapterSortedList.

Sắp xếp danh sách

Do giới hạn ký tự cho câu trả lời trên StackOverflow, tôi không thể thực hiện từng bước triển khai lớp cơ sở này hoặc thậm chí thêm mã nguồn đầy đủ ở đây, nhưng bạn có thể tìm thấy mã nguồn đầy đủ của lớp cơ sở này - tôi đã gọi nó SortedListAdapter- trong này GitHub Gist .

Để làm cho cuộc sống của bạn đơn giản, tôi đã xuất bản một thư viện trên jCenter chứa SortedListAdapter! Nếu bạn muốn sử dụng nó thì tất cả những gì bạn cần làm là thêm phụ thuộc này vào tệp build.gradle của ứng dụng:

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

Bạn có thể tìm thêm thông tin về thư viện này trên trang chủ của thư viện .

Sử dụng SortedListAd CHƯƠNG

Để sử dụng, SortedListAdapterchúng tôi phải thực hiện hai thay đổi:

  • Thay đổi ViewHolderđể nó mở rộng SortedListAdapter.ViewHolder. Tham số loại phải là mô hình nên được ràng buộc với điều này ViewHolder- trong trường hợp này ExampleModel. Bạn phải liên kết dữ liệu với các mô hình của bạn performBind()thay vì 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);
        }
    }
  • Đảm bảo rằng tất cả các mô hình của bạn thực hiện ViewModelgiao diện:

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

Sau đó, chúng tôi chỉ cần cập nhật ExampleAdapterđể mở rộng SortedListAdaptervà xóa mọi thứ chúng tôi không cần nữa. Tham số loại phải là loại mô hình bạn đang làm việc - trong trường hợp này ExampleModel. Nhưng nếu bạn đang làm việc với các loại mô hình khác nhau thì hãy đặt tham số loại thành 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);
    }
}

Sau đó là xong! Tuy nhiên có một điều cuối cùng để đề cập đến: Các SortedListAdapterkhông có cùng add(), remove()hoặc replaceAll()phương pháp ban đầu của chúng tôi ExampleAdapterđã có. Nó sử dụng một Editorđối tượng riêng biệt để sửa đổi các mục trong danh sách có thể được truy cập thông qua edit()phương thức. Vì vậy, nếu bạn muốn xóa hoặc thêm các mục bạn phải gọi edit()thì hãy thêm và xóa các mục trong Editortrường hợp này và sau khi bạn hoàn tất, hãy gọi commit()nó để áp dụng các thay đổi cho SortedList:

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

Tất cả các thay đổi bạn thực hiện theo cách này được gộp lại với nhau để tăng hiệu suất. Các replaceAll()phương pháp chúng tôi thực hiện trong các chương ở trên cũng có mặt trên này Editorđối tượng:

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

Nếu bạn quên gọi commit()thì sẽ không có thay đổi nào của bạn được áp dụng!


4
@TiagoOliveira Vâng, nó được tạo ra để giải quyết vấn đề: D Liên kết dữ liệu là trở ngại cho những người không quen thuộc với nó, nhưng dù sao tôi cũng đưa nó vào vì nó tuyệt vời và tôi muốn quảng bá nó. Vì một số lý do, dường như không nhiều người biết về nó ...
Xaver Kapeller

78
Tôi chưa đọc toàn bộ câu trả lời, tôi đã phải tạm dừng việc đọc ở đâu đó một nửa để viết nhận xét này - đây là một trong những câu trả lời hay nhất tôi tìm thấy ở đây trên SO! Cảm ơn!
daneejela

16
Tôi chỉ thích cách bạn thích: "Không rõ câu hỏi của bạn là gì, vì vậy đây là một ví dụ đầy đủ mà tôi vừa làm": D
Fred

7
+1 chỉ để cho chúng tôi thấy rằng Binding dữ liệu tồn tại trong Android! Tôi chưa bao giờ nghe về điều đó và dường như tôi sẽ bắt đầu sử dụng nó. Cảm ơn
Jorge Casariego

6
Giải pháp này dài vô lý và nói chung là quá kỹ thuật. Đi cho cái thứ hai.
Enrico Casini

194

Tất cả bạn cần làm là thêm filterphương thức vào 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được khởi tạo trong constructor của bộ chuyển đổi như thế nào itemsCopy.addAll(items).

Nếu bạn làm như vậy, chỉ cần gọi filtertừ 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;
    }
});

Đó là một ví dụ từ việc lọc danh bạ của tôi theo tên và số điện thoại.


11
Tôi nghĩ rằng đây nên là câu trả lời được chấp nhận. Nó đơn giản hơn và nó chỉ hoạt động
Jose_GD

6
Đơn giản và hiệu quả!
AlxDroidDev

11
Lưu ý rằng bạn sẽ mất hình ảnh động nếu bạn làm theo phương pháp này thay vì câu trả lời @Xaver Kapeller.
nhục nhã

23
Đừng thử câu trả lời được chấp nhận vì nó quá dài. Câu trả lời này hoạt động và dễ thực hiện. Đừng quên thêm "app: actionViewClass =" android.support.v7.widget.SearchView "trên mục menu XML của bạn.
SajithK

3
Chính xác các mặt hàng và các mặt hàng Bản sao ở đây là gì?
Lucky_girl

82

Theo dõi @Shruthi Kamoji theo cách sạch hơn, chúng ta chỉ có thể sử dụng một bộ lọc, có nghĩa là:

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 ở đây là Loại chung, bạn có thể mở rộng nó bằng lớp của mình:

public class customerAdapter extends GenericRecycleAdapter<CustomerModel>

Hoặc chỉ thay đổi E thành loại bạn muốn (<CustomerModel> ví dụ)

Sau đó, từ searchView (tiện ích bạn có thể đặt trên 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;
    }
});

Tôi sử dụng một cái gì đó như thế này! Hoạt động tốt và mẫu chung!
Mateus

Xin chào, ai có thể giúp tôi từng bước với bước này: stackoverflow.com/questions
40754174 / Fiêu

Câu trả lời sạch nhất!
adalpari

4
Điều này tốt hơn nhiều so với câu trả lời được bình chọn bởi vì thao tác được thực hiện trên một luồng công nhân trong phương thức biểu diễn.
Hmmm

1
Nhưng bạn chỉ định một tham chiếu cho cùng một Danh sách cho các biến khác nhau. Ví dụ this.origenList = list; Bạn nên sử dụng addAll thay thế hoặc vượt qua danh sách trong hàm tạo ArrayList
Florian Walther

5

chỉ cần tạo hai danh sách trong bộ điều hợp một nguồn gốc và một temp và thực hiện Filterable .

    @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();
            }
        };
    }

Ở đâu

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

Giải pháp tốt đẹp. Tôi đã tạo hai danh sách và sử dụng một phương pháp lọc đơn giản. Tôi dường như không thể chuyển vị trí bộ điều hợp chính xác cho một mục cho Hoạt động tiếp theo. Tôi sẽ đánh giá cao bất kỳ suy nghĩ hoặc ý tưởng nào bạn có thể đề xuất cho ý tưởng này: stackoverflow.com/questions/46027110/
mẹo

4

Trong bộ chuyển đổi:

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

Trong hoạt động:

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

Với các Thành phần Kiến trúc Android thông qua việc sử dụng LiveData, điều này có thể dễ dàng thực hiện với bất kỳ loại Bộ điều hợp nào . Bạn chỉ cần thực hiện các bước sau:

1. Thiết lập dữ liệu của bạn để trả về từ Cơ sở dữ liệu phòng dưới dạng LiveData như trong ví dụ dưới đây:

@Dao
public interface CustomDAO{

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

2. Tạo một đối tượng ViewModel để cập nhật dữ liệu của bạn trực tiếp thông qua một phương thức sẽ kết nối DAOUI của bạn

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. Gọi dữ liệu của bạn từ ViewModel một cách nhanh chóng bằng cách chuyển truy vấn thông qua onQueryTextListener như dưới đây:

Bên trong onCreateOptionsMenuthiết lập trình nghe của bạn như sau

searchView.setOnQueryTextListener(onQueryTextListener);

Thiết lập trình nghe truy vấn của bạn ở đâu đó trong lớp SearchActivity của bạn như sau

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);
                                }
                            });
                }
            };

Lưu ý : Các bước (1.) và (2.) là triển khai AAC ViewModelDAO tiêu chuẩn , "ma thuật" thực sự duy nhất đang diễn ra ở đây là trong OnQueryTextListener sẽ cập nhật kết quả danh sách của bạn một cách linh hoạt khi văn bản truy vấn thay đổi.

Nếu bạn cần làm rõ hơn về vấn đề này, xin đừng ngần ngại hỏi. Tôi hy vọng điều này đã giúp :).


1

Đây là nhận định của tôi về việc mở rộng câu trả lời @klimat để không bị mất hoạt ảnh lọc.

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++;
    }
}

Về cơ bản những gì nó làm là xem qua một danh sách đầy đủ và thêm / xóa các mục vào danh sách được lọc từng cái một.


0

Tôi khuyên bạn nên sửa đổi giải pháp của @Xaver Kapeller với 2 điều dưới đây để tránh sự cố sau khi bạn xóa văn bản đã tìm kiếm (bộ lọc không hoạt động nữa) do danh sách phía sau bộ điều hợp có kích thước nhỏ hơn danh sách bộ lọc và IndexOutOfBoundException đã xảy ra. Vì vậy, mã cần phải sửa đổi như dưới đây

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);
    }
}

Và sửa đổi trong chức năng 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); 
    }
}

Hy vọng rằng nó có thể giúp bạn!


Điều đó là không cần thiết.
Xaver Kapeller

Đối với câu trả lời ban đầu nếu bạn không làm điều đó thì IndexOutOfBoundException sẽ xảy ra, vậy tại sao không cần thiết ???? Bạn có muốn một bản ghi? @XaverKapeller
toidv

Không có ngoại lệ sẽ chỉ xảy ra nếu bạn thực hiện Adaptersai cách. Không thấy mã của bạn, tôi đoán vấn đề rất có thể là bạn sẽ không chuyển một bản sao của danh sách với tất cả các mục vào Adapter.
Xaver Kapeller

Nhật ký lỗi: W / System.err: java.lang.IndexOutOfBoundException: Chỉ mục không hợp lệ 36, kích thước là 35 W / System.err: tại java.util.ArrayList.throwIndexOutOfBoundException (ArrayList.java:255) W / System.err: tại java.util.ArrayList.add (ArrayList.java:147) W / System.err: tại com.quomodo.inploi.ui.ad CHƯƠNG.Mult MônSelectFilterAd Module.addItem (NhiềuSelectFilterAd Module.java: 125) W / System.err: .quomodo.inploi.ui.ad CHƯƠNG.MultiplSelectFilterAd Module.applyAndAnimateAdditions (ManySelectFilterAd Module.java:78)
toidv

Vui lòng giúp kiểm tra mã nguồn bên dưới @XaverKapeller gist.github.com/toidv/fe71dc45169e4138271b52fdb29420c5
toidv

0

Recyclerview với searchview và clicklistener

Thêm một giao diện trong bộ chuyển đổi của bạn.

public interface SelectedUser{

    void selectedUser(UserModel userModel);

}

thực hiện giao diện trong tính chính của bạn và ghi đè phương thức. @Override void công khai được chọn Người dùng (UserModel userModel) {

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



}

Hướng dẫn đầy đủ và mã nguồn: Recyclerview với searchview và onclicklistener


-1

Tôi đã giải quyết vấn đề tương tự bằng cách sử dụng liên kết với một số sửa đổi trong đó. Bộ lọc tìm kiếm trên RecyclerView với Thẻ. Nó thậm chí có thể? (hi vọng điêu nay co ich).

Đây là lớp bộ điều hợp của tôi

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);
}
}

// Lớp lọc

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();
}

}

// Lớp hoạt động

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;
}
}

Trong phương thức OnQueryTextChangeListener () sử dụng bộ điều hợp của bạn. Tôi đã phân chia nó thành từng mảnh khi adpter của tôi bị phân mảnh. Bạn có thể sử dụng bộ chuyển đổi trực tiếp nếu nó trong lớp hoạt động của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.