검색 뷰를 사용하여 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에서 제가 이야기하고 있는 모든 작업 사례가 있습니다.
어떤 경우에도 결과는 다음과 같아야 합니다.
데모 앱을 처음 사용하고 싶다면 Play Store에서 설치할 수 있습니다.
아무튼 시작하겠습니다.
SearchView
폴에서 .res/menu
라새파생라는 새 .main_menu.xml
안에 를 설정합니다.actionViewClass
android.support.v7.widget.SearchView
하여 지원라리있지라원네의임사를용여하스를 .actionViewClass
은 다음과 . xml 파일의 은 다음과 같습니다.
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="@string/action_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"/>
</menu>
의 신의에서.Fragment
또는Activity
은 이 xml을. 은 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
에서는 이 방법을 사용하여 두 항목이 동일한 항목을 참조하는지 확인합니다. 말로 ()ㄹ 수 있는지 하지 않고).SortedList
works되어 있는지 합니다.List
추가, 이동 또는 변경 애니메이션을 재생해야 하는 경우모델에 ID가 있으면 일반적으로 이 방법으로 ID만 비교합니다.만약 그들이 그것을 확인하지 않는다면, 당신은 이것을 확인할 다른 방법을 찾을 필요가 있지만, 당신이 이것을 실행하는 것은 당신의 특정 앱에 달려 있습니다.일반적으로 모든 모델에 ID를 지정하는 것이 가장 간단한 옵션입니다. 예를 들어 데이터베이스에서 데이터를 쿼리하는 경우 기본 키 필드가 될 수 있습니다.
과 SortedList.Callback
하면 올르게구경인우생수있성다습니할를스스턴바의 수 .SortedList
:
final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);
번매변서의 에서 첫 SortedList
당신은 당신의 모델들의 수업을 통과해야 합니다. 다매개변단지입니다.SortedList.Callback
위에서 정의했습니다.
이제 본론으로 들어갑시다.만약 우리가 그것을 구현한다면,Adapter
SortedList
다음과 같이 보여야 합니다.
public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {
private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
});
private final LayoutInflater mInflater;
private final Comparator<ExampleModel> mComparator;
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
mInflater = LayoutInflater.from(context);
mComparator = comparator;
}
@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
final ExampleModel model = mSortedList.get(position);
holder.bind(model);
}
@Override
public int getItemCount() {
return mSortedList.size();
}
}
그Comparator
을 정렬할 때하는 것은 할 수 .Adapter
항목을 다른 순서로 표시해야 하는 경우에도 마찬가지입니다.
이제 거의 끝났습니다! 러나그먼저항추가나제방필다요니합법이거는하거하목을▁에 항목을 추가하거나 제거하는 합니다.Adapter
이 목적을 위해 우리는 다음에 방법을 추가할 수 있습니다.Adapter
이를 에 할 수 .SortedList
:
public void add(ExampleModel model) {
mSortedList.add(model);
}
public void remove(ExampleModel model) {
mSortedList.remove(model);
}
public void add(List<ExampleModel> models) {
mSortedList.addAll(models);
}
public void remove(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (ExampleModel model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
가 없습니다. 왜냐하면 '알림'이기 입니다.SortedList
에 대해 이 합니다.SortedList.Callback
한예외를 는 매우 . 즉, 고. 제, 의▁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
가능한 모든 모델 중에서.에서는 " 예에서나만듭다니을음다는이"를 만듭니다.List
ExampleModel
일련의 영화의 인스턴스:
private static final String[] MOVIES = new String[]{
...
};
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
private ExampleAdapter mAdapter;
private List<ExampleModel> mModels;
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mAdapter = new ExampleAdapter(this, ALPHABETICAL_COMPARATOR);
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mBinding.recyclerView.setAdapter(mAdapter);
mModels = new ArrayList<>();
for (String movie : MOVIES) {
mModels.add(new ExampleModel(movie));
}
mAdapter.add(mModels);
}
여기서 특별한 일은 없고, 우리는 단지 예를 들어 설명할 뿐입니다.Adapter
그리고 그것을 다음으로 설정합니다.RecyclerView
그런 다음 다음 다음을 만듭니다.List
에 있는 의.MOVIES
을 배니다입에 합니다. 그런 다음 모든 모델을 추가합니다.SortedList
.
이제 우리는 돌아갈 수 있습니다.onQueryTextChange()
앞에서 정의하고 필터 로직 구현을 시작합니다.
@Override
public boolean onQueryTextChange(String query) {
final List<ExampleModel> filteredModelList = filter(mModels, query);
mAdapter.replaceAll(filteredModelList);
mBinding.recyclerView.scrollToPosition(0);
return true;
}
이것은 다시 한번 매우 직접적입니다.우리는 그 방법을 부릅니다.filter()
그리고 패스를 합니다.List
ExampleModel
쿼리 문자열뿐 아니라그런 다음 전화합니다.replaceAll()
에서.Adapter
필터링된 파일을 전달합니다.List
된환반이 했습니다.filter()
우리는 또한 전화해야 합니다.scrollToPosition(0)
에서.RecyclerView
항목을 검색할 때 사용자가 항상 모든 항목을 볼 수 있도록 합니다. 않으면 그지않 면으렇RecyclerView
필터링 중에 아래로 스크롤된 위치를 유지한 후 몇 가지 항목을 숨길 수 있습니다.맨 위로 스크롤하면 검색하는 동안 더 나은 사용자 환경이 보장합니다.
이제 남은 일은 가상화 환경을 구축하는 것입니다.filter()
자체:
private static List<ExampleModel> filter(List<ExampleModel> models, String query) {
final String lowerCaseQuery = query.toLowerCase();
final List<ExampleModel> filteredModelList = new ArrayList<>();
for (ExampleModel model : models) {
final String text = model.getText().toLowerCase();
if (text.contains(lowerCaseQuery)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
우리가 여기서 제일 먼저 하는 일은 전화입니다.toLowerCase()
쿼리 문자열에 있습니다.검색 기능이 대/소문자를 구분하지 않고 전화로toLowerCase()
비교하는 모든 문자열에서 사례에 관계없이 동일한 결과를 반환할 수 있습니다. 런다 모음모반복다니에 있는 합니다.List
우리는 모델의 텍스트에 쿼리 문자열이 포함되어 있는지 확인합니다. 모델이 모필경이항된추목다에 됩니다.List
.
그게 다야!위의 코드는 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)
.
만약 그렇게 한다면, 그냥 전화하세요.filter
OnQueryTextListener
:
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
adapter.filter(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.filter(newText);
return true;
}
});
이름과 전화번호로 제 전화번호부를 필터링한 예입니다.
@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);
}
DAO와 UI를 연결하는 방법을 통해 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());
}
});
결과:
저는 수정된 링크를 사용하여 동일한 문제를 해결했습니다.카드가 있는 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);
}
}
그것이 당신에게 도움이 되기를 바랍니다!
어댑터에 인터페이스를 추가합니다.
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
'IT' 카테고리의 다른 글
자바스크립트를 사용하여 페이지의 메타 태그를 변경할 수 있습니까? (0) | 2023.08.06 |
---|---|
Controls 컬렉션에서 IEnumberable 메서드를 모두 제공하지 않는 이유는 무엇입니까? (0) | 2023.08.06 |
타임리프를 사용하여 템플릿을 부모 레이아웃으로 래핑 (0) | 2023.08.06 |
PHP: 단어로 된 숫자 표현 (0) | 2023.08.06 |
정의된 간격으로 Android에서 실행 가능한 스레드를 실행하는 방법은 무엇입니까? (0) | 2023.08.06 |