現在、Android Support Library 28.0.0-alpha1からの新しいrecyclerview-selection
APIを実装しようとしており、いくつかの問題に直面しています。私の目標はRecyclerView
、複数の行を選択し、コンテキストアクションバーを表示し、それらに対して「削除」や「共有」などのアクションを実行する機能
何が起こっているのかをよく理解するのに十分なコードを提供してみますが、必要に応じていつでも対応できます。
関心のあるFragment
を含むRecyclerView
で、SelectionTracker
を開始し、RecyclerView.Adapter
に設定します。
private void buildRecyclerView() {
sheetsAdapter = new SheetsAdapter(getContext(), this, sheets);
gridManager = new GridLayoutManager(getContext(), getResources().getInteger(R.integer.grid_span_count));
ItemOffsetDecoration itemDecoration = new ItemOffsetDecoration(getContext(), R.dimen.item_offset);
sheetsRecycler.addItemDecoration(itemDecoration);
sheetsRecycler.setLayoutManager(gridManager);
sheetsRecycler.setAdapter(sheetsAdapter);
sheetsRecycler.setHasFixedSize(true);
SelectionTracker selectionTracker = new SelectionTracker.Builder<>("sheet_selection",
sheetsRecycler,
new StableIdKeyProvider(sheetsRecycler),
new SheetDetailsLookup(sheetsRecycler),
StorageStrategy.createLongStorage())
.withOnContextClickListener(this)
.build();
sheetsAdapter.setSelectionTracker(selectionTracker);
}
これはFragment
内のアイテムのロングクリックをリッスンするためにRecyclerView
もimplements OnContextClickListener
です:
@Override
public boolean onContextClick(@NonNull MotionEvent e) {
if (actionMode != null) {
return false;
}
// Start the CAB using the ActionMode.Callback defined below
if (getActivity() != null) {
actionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(actionModeCallback);
}
return true;
}
そして、それはshouldこのように私のCABを表示します:
private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.sheets_cab_menu, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
Toast.makeText(getContext(), R.string.sheets_delete, Toast.LENGTH_SHORT).show();
mode.finish();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
actionMode = null;
}
};
私のSheetDetailsLookup
は次のようになります。
public class SheetDetailsLookup extends ItemDetailsLookup<Long> {
private RecyclerView recyclerView;
SheetDetailsLookup(RecyclerView recyclerView) {
super();
this.recyclerView = recyclerView;
}
@Nullable
@Override
public ItemDetails<Long> getItemDetails(@NonNull MotionEvent e) {
View view = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (view != null) {
RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view);
if (holder instanceof SheetsAdapter.SheetViewHolder) {
return ((SheetsAdapter.SheetViewHolder) holder).getItemDetails();
}
}
return null;
}
}
SheetViewHolder
で、ビューを更新して、選択されたことを示します。
if (selectionTracker.isSelected(sheet.uid)) {
layout.setBackgroundResource(R.color.md_grey_700);
} else {
layout.setBackgroundResource(Android.R.color.transparent);
}
と同様:
public SheetItemDetails getItemDetails() {
return new SheetItemDetails(getAdapterPosition(), mSheets.get(getAdapterPosition()).uid);
}
SheetItemDetails
は次のとおりです。
public class SheetItemDetails extends ItemDetailsLookup.ItemDetails<Long> {
private int position;
private Long key;
SheetItemDetails(int position, Long key) {
this.position = position;
this.key = key;
}
@Override
public int getPosition() {
return position;
}
@Nullable
@Override
public Long getSelectionKey() {
return key;
}
}
API仕様 に記載されているすべてのものを実装しましたが、現在は問題に直面しています。アイテムを選択してもCABが表示されません...通常、アプリはクラッシュします。このスタックトレースを使用して、選択範囲を「バックアウト」し、ロングクリックして別の選択範囲を開始しようとすると、クラッシュが発生します。
Java.lang.IllegalStateException
at Android.support.v4.util.Preconditions.checkState(Preconditions.Java:130)
at Android.support.v4.util.Preconditions.checkState(Preconditions.Java:142)
at androidx.recyclerview.selection.GestureSelectionHelper.start(GestureSelectionHelper.Java:76)
at androidx.recyclerview.selection.SelectionTracker$Builder$4.run(SelectionTracker.Java:742)
at androidx.recyclerview.selection.TouchInputHandler.onLongPress(TouchInputHandler.Java:136)
at androidx.recyclerview.selection.GestureRouter.onLongPress(GestureRouter.Java:95)
at Android.view.GestureDetector.dispatchLongPress(GestureDetector.Java:779)
at Android.view.GestureDetector.access$200(GestureDetector.Java:40)
at Android.view.GestureDetector$GestureHandler.handleMessage(GestureDetector.Java:293)
at Android.os.Handler.dispatchMessage(Handler.Java:106)
at Android.os.Looper.loop(Looper.Java:164)
at Android.app.ActivityThread.main(ActivityThread.Java:6656)
at Java.lang.reflect.Method.invoke(Native Method)
at com.Android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.Java:438)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:823)
また、アイテムの1つを「ショートクリック」し、詳細ビューを起動する機能を失いました。これまではうまく機能していました。
私は何を間違えましたか?
私は最近このライブラリを調べ始め、同じ例外にとらわれました。この問題は、SelectionTracker
がカスタム_RecyclerView.Adapter
_サブクラスからIDを取得しようとしたときに発生します。この問題を解決するには、まずコンストラクターでsetHasStableIds(true)
を呼び出します。次に、getItemId()
をオーバーライドして、指定された位置パラメーターのIDを返します。
実際、新しいライブラリは今のところ複雑に見えます。新しい最終バージョンを待ってから実装を開始します。確かに、あなたはそれを実験することができますが、私は今のところあなたのアプリでそれを使用しないことをお勧めします。
ニースの新しい機能は1つだけです:指またはマウスを動かすことによる連続的な複数選択。
しかし、私はこれらの例を見つけました:
それまでは、私のようなライブラリを使用することを強くお勧めします。 FlexibleAdapter これは、3年以上の「選択経験」から来ています。複数選択は、 ActionModeHelper
で簡単に使用でき、ActionMode
を使用してコードを簡素化します。関連する Wikiページ を読んでください。
現在、選択はセットに保存されていますが、将来的にアダプター項目自体に委任される可能性があります。ただし、この拡張機能では「選択」を使用できます。
2つのこと:
1)アイテムのクリックに到達するには、OnItemActivatedListener<K>
リスナーを実装し、それへの参照をトラッカービルダーに渡す必要があります。その後、アイテムの「タッチ」を受け取ることができます。
2)コンテキストアクションバーメニューを表示するには、異なるアプローチが必要です。SelectionTracker.SelectionObserver
を実装し、作成後にトラッカーに渡す必要があります:tracker.addObserver(...
。その後、そのオブザーバーで選択変更イベントを受け取ることができます(onSelectionChanged
コールバック経由)。たとえば、選択が開始され(!tracker.getSelection().isEmpty()
=> show CAB)、選択が終了すると(tracker.getSelection()。isEmpty()CABを非表示にします)。単一または複数のアイテムの選択を制御する場合は、トラッカーにSelectionTracker.SelectionPredicate
インスタンスを追加する必要があります(.withSelectionPredicate(
ビルダーメソッドを使用)。
また、@ Code-Apprenticeが示唆しているように、ItemDetailsLookup.ItemDetails
プロバイダーの構築中にgetItemId()
から正しいIDを提供する必要があります(これにより例外が排除されます)。
選択パッケージはまだアルファ版であり、ドキュメントは非常に貧弱であり、それを使用する方法は本当に明確ではありません。自分で試してみましたが、同様の問題があり、最後に SmartRecyclerView を使用しました