[解決済み] RecyclerViewをSearchViewでフィルタリングする方法
質問
を実装しようとしています。
SearchView
をサポートライブラリからダウンロードしました。私は、ユーザーが
SearchView
をフィルタリングするために
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);
}
}
}
解決方法は?
はじめに
ご質問の内容からは、具体的にどのようなことにお困りなのかがよくわかりませんので、この機能をどのように実装するかについて、簡単なチュートリアルを書いてみました。
ここでお話ししているすべての実例は、次のとおりです。 GitHub リポジトリ .
いずれにせよ、結果は次のようになるはずです。
まずはデモアプリで遊んでみたいという方は、Playストアからインストールすることができます。
とにかく始めましょう。
を設定する
SearchView
フォルダー内
res/menu
という名前の新しいファイルを作成します。
main_menu.xml
. その中にアイテムを追加し
actionViewClass
から
android.support.v7.widget.SearchView
. サポートライブラリを使用しているため、サポートライブラリの名前空間を使って
actionViewClass
属性で指定します。あなたのxmlファイルは次のようになるはずです。
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="@string/action_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"/>
</menu>
あなたの
Fragment
または
Activity
の場合は、このメニューXMLを通常のように展開し、その中から
MenuItem
を含む
SearchView
を実装し
OnQueryTextListener
に入力されたテキストの変更をリスンするために使用します。
SearchView
:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
@Override
public boolean onQueryTextChange(String query) {
// Here is where we are going to implement the filter logic
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
そして今度は
SearchView
が使用できるようになりました。フィルタロジックの実装は、後ほど
onQueryTextChange()
を実装し終えたら
Adapter
.
設定する
Adapter
まず第一に、これがこの例で使用するモデル・クラスです。
public class ExampleModel {
private final long mId;
private final String mText;
public ExampleModel(long id, String text) {
mId = id;
mText = text;
}
public long getId() {
return mId;
}
public String getText() {
return mText;
}
}
これは基本的なモデルであり、テキストを
RecyclerView
. これは、テキストを表示するために使用するレイアウトです。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="model"
type="com.github.wrdlbrnft.searchablerecyclerviewdemo.ui.models.ExampleModel"/>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="@{model.text}"/>
</FrameLayout>
</layout>
見ての通り、私はデータバインディングを使っています。もしあなたがデータバインディングを使ったことがなくても、がっかりしないでください。データバインディングはとてもシンプルで強力ですが、この回答ではその仕組みは説明できません。
これは
ViewHolder
に対して
ExampleModel
クラスがあります。
public class ExampleViewHolder extends RecyclerView.ViewHolder {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
public void bind(ExampleModel item) {
mBinding.setModel(item);
}
}
ここでも特別なことは何もありません。上記のレイアウトxmlで定義したように、モデルクラスをこのレイアウトにバインドするためにデータバインディングを使用するだけです。
さて、いよいよ本当に面白い部分に入ります。アダプタを書くことです。の基本的な実装は省略します。
Adapter
その代わりに、この答えに関連する部分に集中するつもりです。
しかし、その前にひとつだけ話しておかなければならないことがあります。それは
SortedList
クラスがあります。
ソートリスト
は
SortedList
の一部である、まったく驚くべきツールです。
RecyclerView
ライブラリです。このライブラリは
Adapter
は、データセットの変更について、非常に効率的な方法で行います。唯一必要なことは、要素の順序を指定することである。これを行うには
compare()
メソッドにある2つの要素を比較します。
SortedList
と同じように
Comparator
. しかし
List
の項目をソートするために使用されます。
RecyclerView
!
は
SortedList
と対話します。
Adapter
を介して
Callback
クラスを実装する必要があります。
private final SortedList.Callback<ExampleModel> mCallback = new SortedList.Callback<ExampleModel>() {
@Override
public void onInserted(int position, int count) {
mAdapter.notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
mAdapter.notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
mAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
mAdapter.notifyItemRangeChanged(position, count);
}
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
}
のようなコールバックの先頭のメソッドに
onMoved
,
onInserted
のnotifyメソッドを呼び出す必要があります。
Adapter
. 下部の3つのメソッド
compare
,
areContentsTheSame
と
areItemsTheSame
は、どのようなオブジェクトをどのような順番で表示させるかによって、実装する必要があります。
それでは、これらのメソッドを一つずつ見ていきましょう。
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
これは
compare()
メソッドについて説明しました。この例では、単に呼び出しを
Comparator
で、2つのモデルを比較します。もし、画面にアルファベット順で表示させたい場合。このコンパレータは次のようになります。
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
は、change イベントを呼び出す必要があるかどうかを判断するためにこれを使用します。
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;
}
}
補足:Android Studio、IntelliJ、Eclipseなど、ほとんどのIDEには
equals()
と
hashCode()
をボタン一つで実装してくれます。だから、自分で実装する必要はないのです。IDEでどう動くかはネットで調べてね!
では、最後のメソッドを見てみましょう。
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
は
SortedList
は、2つの項目が同じものを参照しているかどうかをチェックするためにこのメソッドを使用します。最も単純に言えば、(どのように
SortedList
の動作) にすでに含まれているかどうかを判断するために使用されます。
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();
}
ここでは、notifyメソッドを呼び出す必要はありません。
SortedList
はすでに
SortedList.Callback
! を削除する remove メソッドです。
List
のモデルで構成されています。というのは
SortedList
は1つのオブジェクトを削除できるremoveメソッドしか持っていないので、リスト上をループしてモデルを1つずつ削除していく必要があります。呼び出し
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
よりシンプルになりました。
問題の一般化とアダプタの簡略化
このセクションでは、あまり詳細には触れません - Stack Overflowの回答の文字数制限にぶつかっていることもありますが、ほとんどはすでに上で説明されているからです - が、変更点をまとめると、以下のようになります。私たちは、ベースとなる
Adapter
クラスは、すでに
SortedList
へのモデルのバインディングと同様に
ViewHolder
インスタンスを実装する便利な方法を提供します。
Adapter
をベースにした
SortedList
. そのためには、2つのことをしなければなりません。
-
を作成する必要があります。
ViewModel
インターフェイスを実装する必要があります。 -
を作成する必要があります。
ViewHolder
サブクラスはbind()
メソッドを使用します。Adapter
は、モデルを自動的にバインドするために使用することができます。
これによって、本来は
RecyclerView
を実装するだけで、モデルとそれに対応する
ViewHolder
を実装しています。この基本クラスを使用すると、私たちは
Adapter
とその
SortedList
.
SortedListAdapter
StackOverflowの回答の文字数制限のため、このベースクラスの実装の各ステップを説明したり、完全なソースコードをここに追加することはできませんが、このベースクラスの完全なソースコードを見ることができます - 私はこのクラスを
SortedListAdapter
- この中で
GitHub Gist
.
あなたの生活を簡単にするために、私はjCenterでライブラリを公開しました。
SortedListAdapter
! これを使いたい場合は、アプリの build.gradle ファイルにこの依存関係を追加すればよいのです。
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.1'
このライブラリに関するより詳しい情報を見ることができます 図書館のホームページで .
SortedListAdapter の使用法
を使用するには
SortedListAdapter
は、2つの変更を行う必要があります。
-
を変更します。
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
を作成し、不要なものをすべて削除します。typeパラメータは、作業しているモデルのタイプである必要があります - この場合
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()
メソッドで、オリジナルの
ExampleAdapter
が持っていた。これは別の
Editor
オブジェクトを通してアクセスできるリストの項目を修正します。
edit()
メソッドを使用します。ですから、アイテムを削除したり追加したりしたい場合は
edit()
で項目を追加したり削除したりします。
Editor
インスタンスを作成し、完了したら
commit()
に変更を適用するために、その上に
SortedList
:
mAdapter.edit()
.remove(modelToRemove)
.add(listOfModelsToAdd)
.commit();
この方法で行ったすべての変更は、パフォーマンスを向上させるために一括して行われます。そのため
replaceAll()
メソッドは、上記の章で実装したこの
Editor
オブジェクトを作成します。
mAdapter.edit()
.replaceAll(mModels)
.commit();
を呼び出すのを忘れた場合
commit()
この場合、変更は一切適用されません。
関連
-
ActivityはOnFragmentInteractionListenerを実装しなければならないに関する質問
-
アンドロイドスタジオでJunitのエラー問題を解決する
-
android exception - aapt.exe has stopped working.
-
view.getRootView()の本当の意味とテストについて
-
アンドロイドスタジオ学習入門
-
アンドロイドにおけるトークンの利用
-
android.content.ActivityNotFoundException を解決します。Intent問題を処理するActivityが見つからない
-
[解決済み] Androidのソフトキーボードをプログラムで閉じる/隠すにはどうすればよいですか?
-
[解決済み] Androidでアクティビティ起動時にEditTextにフォーカスが当たらないようにする方法
-
[解決済み] RecyclerView onClick
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
android.os の NetworkOnMainThreadException。
-
Gradle のエラーです。gradle-core.jar (com.android.tools.build:gradle-core:x.x.x) を見つけられませんでした。
-
gitlab 設定エラー。リモートリポジトリから読み込めなかったか、ホストキーの検証に失敗しました。
-
AndroidStudio reports Could not resolve all artifacts for configuration ':app:classpath'.
-
例外「指定された子にはすでに親がいます」の解決方法。removeViewを呼び出す必要があります" の解決方法(ソースコード付き例)
-
GoogleMapと連携し、位置情報の取得が可能
-
WeChatとQQは、他のアプリのオープンリストに自分のアプリを追加し、ファイルパスを取得することができます
-
Android Bluetooth 開発の基本プロセス
-
アンドロイドスタジオソフトウェア使用詳細説明書
-
Android Studioのgitの使用とgitの設定パス