Android recyclerview-selection实施?

dri*_*noo 6 android multipleselection android-actionmode android-recyclerview

我目前正在尝试recyclerview-selection从Android支持库28.0.0-alpha1 实现新的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);
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

应该显示我的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;
    }
};
Run Code Online (Sandbox Code Playgroud)

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;
}
}
Run Code Online (Sandbox Code Playgroud)

在我的SheetViewHolder,我更新视图,以表明它已被选中:

if (selectionTracker.isSelected(sheet.uid)) {
            layout.setBackgroundResource(R.color.md_grey_700);
        } else {
            layout.setBackgroundResource(android.R.color.transparent);
        }
Run Code Online (Sandbox Code Playgroud)

以及:

public SheetItemDetails getItemDetails() {
        return new SheetItemDetails(getAdapterPosition(), mSheets.get(getAdapterPosition()).uid);
    }
Run Code Online (Sandbox Code Playgroud)

其中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;
}
}
Run Code Online (Sandbox Code Playgroud)

我已经实现了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)
Run Code Online (Sandbox Code Playgroud)

此外,我现在已经失去了"短按"我的一个项目的能力,以启动详细视图......到目前为止我工作得很好.

我做错了什么?

Cod*_*ice 6

我最近开始查看此库,并遇到了相同的异常。当SelectionTracker尝试从您的自定义RecyclerView.Adapter子类中获取ID 时,会发生此问题。要解决此问题,请先调用setHasStableIds(true)其构造函数。然后覆盖getItemId()以返回给定位置参数的ID。

  • @Micklo_Nerd 是的,我也觉得它很复杂。 (3认同)
  • 好的 我只是觉得这太复杂了 (2认同)

gre*_*f82 0

选择包仍处于 alpha 阶段,文档相当差,并且不太清楚如何使用它。我自己尝试过,但也遇到了类似的问题,最后我使用了SmartRecyclerView