我目前正在尝试从Android支持库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
也implements OnContextClickListener
,以便倾听我RecyclerView
中项目的长按:
@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;
}
它应该 显示我的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 specification中提到的所有内容,但现在遇到了麻烦。当我选择一个项目时,我的CAB不显示...而且应用程序通常会崩溃。每当我尝试&#34;退出&#34;时就会发生崩溃。选择,然后长按以开始另一个选择,使用此堆栈跟踪:
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)
此外,我现在已经失去了&#34;短按&#34;在我的一个项目上,发布一个详细视图......到目前为止我工作得很好。
我做错了什么?
答案 0 :(得分:4)
我最近开始查看该库,并遇到了相同的异常。当SelectionTracker
试图从您的自定义RecyclerView.Adapter
子类中获取ID时,就会发生问题。要解决此问题,请先在其构造函数中调用setHasStableIds(true)
。然后覆盖getItemId()
以返回给定位置参数的ID。
答案 1 :(得分:2)
新图书馆现在看起来很复杂。在开始实施之前,我会等待新的最终版本。当然,您可以尝试使用它,但我建议您暂时不要在应用中使用它。
只有一个不错的新功能:通过移动手指或鼠标来实现连续多选。
但是,我找到了这些例子:
与此同时,我强烈建议使用像我这样的库:FlexibleAdapter,它来自超过3年的“选择经验”,它不会在(de)选择发生时绑定项目!使用ActionModeHelper
进行多项选择很简单,可以使用ActionMode
简化代码。阅读相关的Wiki page。
目前,选择内容保存在Set中,但将来可能会将其委托给适配器项本身。但是,您可以对此扩展程序使用“选择”。
答案 2 :(得分:0)
选择包仍处于alpha状态,文档很差,并且不太清楚如何使用它。我试过自己,但我遇到了类似的问题,最后我使用了SmartRecyclerView
答案 3 :(得分:0)
两件事:
1)要点击项目,您需要实现一个OnItemActivatedListener<K>
侦听器,并将对它的引用传递给跟踪器构建器。之后,您可以在项目上收到“触摸”。
2)要显示上下文操作栏菜单,需要使用不同的方法:您需要实现SelectionTracker.SelectionObserver
,并将其创建后传递给跟踪器:tracker.addObserver(...
。之后,您可以在该观察器中接收选择更改事件(通过onSelectionChanged
回调)。例如,当选择开始(!tracker.getSelection().isEmpty()
=>显示CAB)并且选择结束(tracker.getSelection()。isEmpty()隐藏CAB)时。
如果要控制单个/多个项目的选择,则必须为跟踪器添加SelectionTracker.SelectionPredicate
实例(通过.withSelectionPredicate(
构建器方法)。
并且,正如@ Code-Apprentice所建议的那样,您在构造getItemId()
提供程序时需要从ItemDetailsLookup.ItemDetails
提供正确的ID(这消除了异常)。