IT

검색 뷰를 사용하여 Recycler 뷰를 필터링하는 방법

itgroup 2023. 8. 6. 09:59
반응형

검색 뷰를 사용하여 Recycler 뷰를 필터링하는 방법

나는 그것을 구현하기 위해 노력하고 있습니다.SearchView지원 라이브러리에서.가 나는사사원합다니를기용하가용을 .SearchView▁a▁List화의영의 의.RecyclerView.

지금까지 몇 가지 튜토리얼을 따라왔고 다음을 추가했습니다.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);
        }
    }
}

소개

귀하의 질문에서 정확히 무엇에 문제가 있는지 명확하지 않기 때문에, 이 기능을 구현하는 방법에 대한 간단한 설명을 작성했습니다. 질문이 남아 있으면 언제든지 질문하십시오.

깃헙 Repository에서 제가 이야기하고 있는 모든 작업 사례가 있습니다.

어떤 경우에도 결과는 다음과 같아야 합니다.

demo image

데모 앱을 처음 사용하고 싶다면 Play Store에서 설치할 수 있습니다.

Get it on Google Play

아무튼 시작하겠습니다.


SearchView

폴에서 .res/menu라새파생라는 새 .main_menu.xml 안에 를 설정합니다.actionViewClassandroid.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을. 은 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;
}

그고이제는리▁and.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의 일부인 완전히 놀라운 도구입니다.RecyclerView도서관.다음과 같이 알림을 처리합니다.Adapter데이터 세트의 변경사항에 대해 설명하고 매우 효율적인 방법으로 변경합니다.요소의 순서를 지정하면 됩니다.이를 위해 다음을 구현해야 합니다.compare() 방는법의 두 SortedList 꼭▁aComparator하지만 정렬하는 대신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당신은 의▁of▁▁your▁notify▁theent▁의 동등한 통지 방법을 불러야 .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;
    }
}

파일: Studio,IDE는 Android Studio, IntelliJ Eclipse를 생성하는 있습니다.equals()그리고.hashCode()버튼 하나만 누르면 구현할 수 있습니다!따라서 직접 구현할 필요가 없습니다.IDE에서 작동하는지 ! IDE에서 IDE를 찾아보세요!

이제 마지막 방법을 살펴보겠습니다.

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

SortedList에서는 이 방법을 사용하여 두 항목이 동일한 항목을 참조하는지 확인합니다. 말로 ()ㄹ 수 있는지 하지 않고).SortedListworks되어 있는지 합니다.List추가, 이동 또는 변경 애니메이션을 재생해야 하는 경우모델에 ID가 있으면 일반적으로 이 방법으로 ID만 비교합니다.만약 그들이 그것을 확인하지 않는다면, 당신은 이것을 확인할 다른 방법을 찾을 필요가 있지만, 당신이 이것을 실행하는 것은 당신의 특정 앱에 달려 있습니다.일반적으로 모든 모델에 ID를 지정하는 것이 가장 간단한 옵션입니다. 예를 들어 데이터베이스에서 데이터를 쿼리하는 경우 기본 키 필드가 될 수 있습니다.

SortedList.Callback하면 올르게구경인우생수있성다습니할를스스턴바의 수 .SortedList:

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

번매변서의 에서 첫 SortedList당신은 당신의 모델들의 수업을 통과해야 합니다. 다매개변단지입니다.SortedList.Callback위에서 정의했습니다.

이제 본론으로 들어갑시다.만약 우리가 그것을 구현한다면,AdapterSortedList다음과 같이 보여야 합니다.

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한예외를 는 매우 . 즉, 고. 제, 의▁a▁which▁method▁aside▁removes다▁remove▁is▁the니:제를 제거하는 제거 방법입니다.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가능한 모든 모델 중에서.에서는 " 예에서나만듭다니을음다는이"를 만듭니다.ListExampleModel일련의 영화의 인스턴스:

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()그리고 패스를 합니다.ListExampleModel쿼리 문자열뿐 아니라그런 다음 전화합니다.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.

그게 다야!위의 코드는 API 레벨 7 이상에서 실행되며 API 레벨 11부터는 아이템 애니메이션을 무료로 받을 수 있습니다.

이보다 더 있습니다. 가 이 하고 실행할 수 있는 .Adapter에의여하에 SortedList훨씬 간단한


문제 일반화 및 어댑터 단순화

Overflow에 위에서 사항을 . 리는기구수있다니습현할우를지ed▁base를 구현할 수 있습니다.Adapter 미이처는클스래하리▁▁with▁the▁takes를 다루는 수업SortedList을 모을에 아니뿐라만에 만 아니라ViewHolder하게 구현할 수 있는 방법을 구현하는 편리한 합니다.Adapter에의여하에 SortedList그러기 위해서는 다음 두 가지를 수행해야 합니다.

  • 우리는 그것을 만들 필요가 있습니다.ViewModel입니다.
  • 우리는 그것을 만들 필요가 있습니다.ViewHolder를 하는 하위 bind() 더 메소드Adapter를 사용하여 모델을 자동으로 바인딩할 수 있습니다.

이것은 우리가 단지 표시되어야 하는 내용에 초점을 맞출 수 있게 해줍니다.RecyclerView에 상응하는 모델을 으로써.ViewHolder실행.이 기본 클래스를 사용하면 복잡한 세부 사항에 대해 걱정할 필요가 없습니다.Adapter그리고 그것들SortedList.

정렬된 목록 어댑터

이각를 여기에할 수도 이 클래스의 수 . - StackOverflow라고 .SortedListAdapter깃허브 기스트에서.

위해 을 게시했습니다. 에는 "jCenter에는 "jCenter"라는 라이브러리가 .SortedListAdapter사용하려면 앱의 build.gradle 파일에 이 종속성을 추가하기만 하면 됩니다.

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

도서관에 대한 더 많은 정보는 도서관 홈페이지에서 찾을 수 있습니다.

정렬된 목록 어댑터 사용

용방법을 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 다른 를 type 로 설정합니다.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()의 원래 우리의인방법적창독방▁original▁our.ExampleAdapter 써요. 그것은 별도로 사용합니다.Editor는 에서 수 .edit() 아이템을 '아이템을 제거한다'라고 불러야 .edit() 이 그다음 이항및제다에 합니다.Editor인스턴스를 수행하고 완료되면 전화를 겁니다.commit()변경 사항을 적용하기 위해.SortedList:

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

이러한 방식으로 변경하는 모든 내용은 성능을 향상시키기 위해 함께 배치됩니다.replaceAll()가 위의 이▁this▁we▁▁on에도 있습니다.Editor객체:

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

전화하는 것을 잊어버린 경우commit()그러면 변경 사항이 적용되지 않습니다!

이 해야 할 일은 됩다니하면만을 추가하는 입니다.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).

만약 그렇게 한다면, 그냥 전화하세요.filterOnQueryTextListener:

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

이름과 전화번호로 제 전화번호부를 필터링한 예입니다.

@Shruthi Kamoji를 더 깨끗한 방식으로 따라가면 필터를 사용할 수 있습니다. 이는 다음을 의미합니다.

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

일반 유형입니다. 클래스를 사용하여 확장할 수 있습니다.

public class customerAdapter extends GenericRecycleAdapter<CustomerModel>

그냥 (또 E 원 유 변 경 합 니 다 로 를 으 형 는 하 는 ( 니 다 ▁or 합 또 경변 ▁the ▁change<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;
    }
});

어댑터 내:

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

어댑터 하나 또는 신호 하나에 두 개의 목록을 만들고 하나의 temp를 생성하여 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();
            }
        };
    }

어디에

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

LiveData사용하는 Android Architecture Components를 사용하면 모든 유형의 어댑터로 쉽게 구현할 수 있습니다.다음 단계를 수행하기만 하면 됩니다.

다음 예와 같이 룸 데이터베이스에서 LiveData로 반환하도록 데이터를 설정합니다.

@Dao
public interface CustomDAO{

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

DAOUI를 연결하는 방법을 통해 ViewModel 개체를 생성하여 데이터를 실시간으로 업데이트합니다.

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

}

아래와 같이 QueryTextListener에서 쿼리를 전달하여 ViewModel에서 데이터를 즉시 호출할 수 있습니다.

에 안에.onCreateOptionsMenu과 같이 합니다.

searchView.setOnQueryTextListener(onQueryTextListener);

다음과 같이 검색 활동 클래스의 어딘가에 쿼리 수신기를 설정합니다.

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.) 단계는 표준 AAC View Model 및 DAO 구현이며, 여기서 진행되는 유일한 "마법"은 쿼리 텍스트가 변경될 때 목록의 결과를 동적으로 업데이트하는 OnQueryTextListener있습니다.

만약 당신이 그 문제에 대해 더 명확한 설명이 필요하다면 주저하지 말고 물어보세요.이것이 도움이 되었기를 바랍니다 :).

왜 모두가 같은 목록을 2부씩 사용해서 해결하는지 모르겠습니다.RAM을 너무 많이 사용합니다...

찾을 수 없는 요소를 숨기고 인덱스를 저장하는 것이 어떻습니까?Set나중에 복구할 수 있을까요?특히 객체가 상당히 큰 경우 RAM이 훨씬 적습니다.

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.SampleViewHolders>{
    private List<MyObject> myObjectsList; //holds the items of type MyObject
    private Set<Integer> foundObjects; //holds the indices of the found items

    public MyRecyclerViewAdapter(Context context, List<MyObject> myObjectsList)
    {
        this.myObjectsList = myObjectsList;
        this.foundObjects = new HashSet<>();
        //first, add all indices to the indices set
        for(int i = 0; i < this.myObjectsList.size(); i++)
        {
            this.foundObjects.add(i);
        }
    }

    @NonNull
    @Override
    public SampleViewHolders onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View layoutView = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.my_layout_for_staggered_grid, null);
        MyRecyclerViewAdapter.SampleViewHolders rcv = new MyRecyclerViewAdapter.SampleViewHolders(layoutView);
        return rcv;
    }

    @Override
    public void onBindViewHolder(@NonNull SampleViewHolders holder, int position)
    {
        //look for object in O(1) in the indices set
        if(!foundObjects.contains(position))
        {
            //object not found => hide it.
            holder.hideLayout();
            return;
        }
        else
        {
            //object found => show it.
            holder.showLayout();
        }

        //holder.imgImageView.setImageResource(...)
        //holder.nameTextView.setText(...)
    }

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

    public void findObject(String text)
    {
        //look for "text" in the objects list
        for(int i = 0; i < myObjectsList.size(); i++)
        {
            //if it's empty text, we want all objects, so just add it to the set.
            if(text.length() == 0)
            {
                foundObjects.add(i);
            }
            else
            {
                //otherwise check if it meets your search criteria and add it or remove it accordingly
                if (myObjectsList.get(i).getName().toLowerCase().contains(text.toLowerCase()))
                {
                    foundObjects.add(i);
                }
                else
                {
                    foundObjects.remove(i);
                }
            }
        }
        notifyDataSetChanged();
    }

    public class SampleViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener
    {
        public ImageView imgImageView;
        public TextView nameTextView;

        private final CardView layout;
        private final CardView.LayoutParams hiddenLayoutParams;
        private final CardView.LayoutParams shownLayoutParams;

        
        public SampleViewHolders(View itemView)
        {
            super(itemView);
            itemView.setOnClickListener(this);
            imgImageView = (ImageView) itemView.findViewById(R.id.some_image_view);
            nameTextView = (TextView) itemView.findViewById(R.id.display_name_textview);

            layout = itemView.findViewById(R.id.card_view); //card_view is the id of my androidx.cardview.widget.CardView in my xml layout
            //prepare hidden layout params with height = 0, and visible layout params for later - see hideLayout() and showLayout()
            hiddenLayoutParams = new CardView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            hiddenLayoutParams.height = 0;
            shownLayoutParams = new CardView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
        }

        @Override
        public void onClick(View view)
        {
            //implement...
        }

        private void hideLayout() {
            //hide the layout
            layout.setLayoutParams(hiddenLayoutParams);
        }

        private void showLayout() {
            //show the layout
            layout.setLayoutParams(shownLayoutParams);
        }
    }
}

그리고 나는 단지.EditText상자로: 사용자 이름:

cardsSearchTextView.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                myViewAdapter.findObject(editable.toString().toLowerCase());
            }
        });

결과:

Search example gif

저는 수정된 링크를 사용하여 동일한 문제를 해결했습니다.카드가 있는 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() 메서드에서 어댑터를 사용합니다.제 어댑터가 조각나 있기 때문에 조각으로 주조했습니다.어댑터가 활동 클래스에 있는 경우 어댑터를 직접 사용할 수 있습니다.

이것은 필터링 애니메이션을 잃지 않는 @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++;
    }
}

기본적으로 전체 목록을 살펴보고 필터링된 목록에 항목을 하나씩 추가/제거합니다.

어댑터의 목록 백이 필터 목록보다 크기가 작고 IndexOutOfBoundsException이 발생하여 검색된 텍스트(필터가 더 이상 작동하지 않음)를 지운 후 문제가 발생하지 않도록 하기 위해 아래의 두 가지 사항으로 @XaverKapler 솔루션을 수정할 것을 권장합니다.그래서 코드를 아래와 같이 수정해야 합니다.

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

그리고 이동 중 항목 기능도 수정합니다.

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

그것이 당신에게 도움이 되기를 바랍니다!

Recyclerview with searchview and clicklistener

어댑터에 인터페이스를 추가합니다.

public interface SelectedUser{

    void selectedUser(UserModel userModel);

}

기본 활동에서 인터페이스를 구현하고 메서드를 재정의합니다.@선택한 사용자(사용자 모델 사용자 모델) {공용 void 재정의

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



}

전체 자습서 및 소스 코드:검색 보기 및 온클릭 수신기를 사용한 재활용 보기

버튼을 클릭하여 검색하려면 이 작업이 잘 작동합니다.

filterIcon.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String strCHR = homeSearchEdit.getText().toString();
        if (homeSearchEdit.getText().toString().length() > 0) {
            ArrayList<ServiceModel> listNew = new ArrayList<>();
            for (int l = 0; l < arrayList.size(); l++) {
                String serviceName = arrayList.get(l).getServiceName().toLowerCase();
                if (serviceName.contains(strCHR.toLowerCase())) {
                    listNew.add(arrayList.get(l));
                }
            }
            recyclerView.setVisibility(View.VISIBLE);
            adapter = new ServiceAdapter(HomeActivity.this, listNew);
            recyclerView.setAdapter(adapter);
        } else {
            recyclerView.setVisibility(View.VISIBLE);
            adapter = new ServiceAdapter(HomeActivity.this, arrayList);
            recyclerView.setAdapter(adapter);
        }
    }
});

여기서 filterIcon은 버튼이고 homeSearchEdit는 editText(검색을 신청하는 곳)입니다.

는 Android를 했습니다.DiffUtil.Callback()그리고.DiffUtil.ItemCallback<T>그리고 그들은 우리가 재활용자의 관점을 잘 필터링할 수 있도록 도와줍니다.

DiffUtil은 두 목록 간의 차이를 계산하고 첫 번째 목록을 두 번째 목록으로 변환하는 업데이트 작업 목록을 출력하는 유틸리티 클래스입니다.

https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil

DiffUtiffUtil.콜백()은 RecyclerView와 함께 사용됩니다.어댑터

그리고.

DiffUtiffUtil.ItemCallback이 ListAdapter와 함께 사용됩니다.

RecyclerView를 사용하여 필터링

일반적으로 재지정하는 것처럼 재활용자 뷰를 만듭니다.

onCreateViewHolder

onBindViewHolder

getItemCount

리고확장을 합니다.RecyclerView.ViewHolder Class

당신이 한 것처럼 (이것은 당신의 코드에 있는 코틀린 버전의 스니펫입니다)

override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder? {
    val v: View = LayoutInflater.from(viewGroup.context)
        .inflate(R.layout.recycler_view_card_item, viewGroup, false)
    return ViewHolder(v)
}

fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
    val movie: Movie = mItems.get(i)
    viewHolder.tvMovie.setText(movie.getName())
    viewHolder.tvMovieRating.setText(movie.getRating())
}

override fun getItemCount(): Int {
    return mItems.size()
}

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var tvMovie: TextView
    var tvMovieRating: TextView

    init {
        tvMovie = itemView.findViewById<View>(R.id.movieName) as TextView
        tvMovieRating = itemView.findViewById<View>(R.id.movieRating) as TextView
    }
}

이제 DiffUtil을 구현할 다른 클래스를 만듭니다.콜백()

이 클래스는 재활용품 보기 현재 목록을 필터링된 목록으로 변환하는 데 도움이 됩니다.

class MoviesDiffUtilCallback(private val oldList: List<Movies>, private val newList: List<Movies>) : DiffUtil.Callback() {

override fun getOldListSize() = oldList.size

override fun getNewListSize() = newList.size

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = oldList[oldItemPosition].aUniqueId == newList[newItemPosition]. aUniqueId

//aUniqueId-> a field that is unique to each item in your listItems

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = oldList[oldItemPosition] == newList[newItemPosition]

}

활동 또는 단편화 클래스 설정에서 어댑터와 필터를 설정합니다.

private fun setupAdapter() {

//mItems is the list you will pass to the adapter
        adapter = CardAdapter(mItems)

        recyclerView.adapter = adapter

}

fun filter(searchText : String){

    val newFilter = mItems.filter {

        it.name.lowercase().contains(text.lowercase()) //filterlogic

    }

//Calculate the list of update operations that can covert one list into the other one 
    val diffResult = DiffUtil.calculateDiff(PostsDiffUtilCallback(mItems,newFilter))

    mItems.clear()


    mItems.addAll(newFilter)

//dispatch all updates to the RecyclerView
    diffResult.dispatchUpdatesTo(adapter)

}

목록 어댑터를 사용하여 필터링

필터링 가능한 인터페이스를 사용하여 필터링할 것입니다(필터링 기능을 사용하여 목록을 가져오고 목록(필터링된 목록)을 직접 제출하면 안 되는 이유는 여전히 파악 중입니다).

ListAdapter 클래스 만들기

class CardAdapter (
private val mItems : List<Movies>) : ListAdapter<Movies, CardAdapter.BillsPackageViewHolder>(MoviesDiffCallback()),
Filterable {

override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder? {
    val v: View = LayoutInflater.from(viewGroup.context)
        .inflate(R.layout.recycler_view_card_item, viewGroup, false)
    return ViewHolder(v)
}

fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
    val movie: Movie = mItems.get(i)
    viewHolder.tvMovie.setText(movie.getName())
    viewHolder.tvMovieRating.setText(movie.getRating())
}


override fun getFilter(): Filter {

    return object : Filter() {

        override fun performFiltering(constraint: CharSequence?): FilterResults {

            return FilterResults().apply {

                values = if (constraint.isNullOrEmpty())
                    mItems
                else
                    onFilter(mItems, constraint.toString())
            }
        }

        @Suppress("UNCHECKED_CAST")
        override fun publishResults(constraint: CharSequence?, results: FilterResults?) {

            submitList(results?.values as? List<Movies>)

        }
    }

}

fun onFilter(list: List<Movies>, constraint: String) : List<Movies>{

    val filteredList = list.filter {

        it.name.lowercase().contains(constraint.lowercase())

    }

    return filteredList

}

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var tvMovie: TextView
    var tvMovieRating: TextView

    init {
        tvMovie = itemView.findViewById<View>(R.id.movieName) as TextView
        tvMovieRating = itemView.findViewById<View>(R.id.movieRating) as TextView
    }
}
}

이제 DiffUtil을 구현할 다른 클래스를 만듭니다.항목 콜백

class MoviesDiffCallback : DiffUtil.ItemCallback<Movies>() {

override fun areItemsTheSame(oldItem: Movies, newItem: Movies): Boolean {
    return oldItem.someUniqueid == newItem.someUniqueid
}

override fun areContentsTheSame(oldItem: Movies, newItem: Movies): Boolean {
    return oldItem == newItem
}
}

그리고 메인 Activity 또는 Fragment Setup에서 어댑터와 필터를 사용됩니다.

private fun setupAdapter() {

    adapter = CardAdapter(mItems)

    recyclerView.adapter = adapter

}

fun filter(searchString : String){

    adapter.filter.filter(searchString)

}

언급URL : https://stackoverflow.com/questions/30398247/how-to-filter-a-recyclerview-with-a-searchview

반응형