当我第一次使用普通适配器遇到这个问题时,我最终创建了自己的自定义 View 子类并在其中存储了我需要的东西。我真的不喜欢那个解决方案,花了很多时间研究人们提出的好主意,并决定我不喜欢它们了。所以我把所有东西放在一起,摇晃了一会儿,然后拿出了一些我喜欢的新东西。
我们从几个实用程序类开始。
ContextMenuHandler 是用于处理上下文菜单的任何对象的接口。在实践中,这将是一个 ViewHolder 子类,但理论上它可以是任何东西
/**
* Interface for objects that wish to create and handle selections from a context
* menu associated with a view
*/
public interface ContextMenuHandler extends View.OnCreateContextMenuListener {
boolean onContextItemSelected(MenuItem item);
}
Next 是一个必须由任何将用作 RecyclerView 的直接子级的 View 实现的接口。
public interface ViewWithContextMenu {
public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler);
public ContextMenuHandler getContextMenuHandler();
}
接下来,要创建上下文菜单作为 RecylcerView 的子级的任何视图都必须实现 ViewWIthContextMenu。在我的例子中,我只需要一个 LinearLayout 的子类。
public class LinearLayoutWithContextMenu extends LinearLayout implements ViewWithContextMenu {
public LinearLayoutWithContextMenu(Context context) {
super(context);
}
public LinearLayoutWithContextMenu(Context context, AttributeSet attrs) {
super(context, attrs);
}
private ContextMenuHandler handler;
@Override
public void setContextMenuHandler(FragmentWithContextMenu fragment, ContextMenuHandler handler) {
this.handler = handler;
setOnCreateContextMenuListener(fragment);
}
@Override
public ContextMenuHandler getContextMenuHandler() {
return handler;
}
}
最后,我们需要一个增强的 Fragment 类来拦截上下文菜单调用并将它们重定向到适当的处理程序。
public class FragmentWithContextMenu extends Fragment {
ContextMenuHandler handler = null;
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
handler = null;
if (view instanceof ViewWithContextMenu) {
handler = ((ViewWithContextMenu)view).getContextMenuHandler();
if (handler != null) handler.onCreateContextMenu(menu, view, menuInfo);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (handler != null) {
if (handler.onContextItemSelected(item)) return true;
}
return super.onContextItemSelected(item);
}
}
有了所有这些,最终的实现就非常简单了。主片段必须是 FragmentWithContextMenu 的子类。它正常设置主 RecylerWindow 并将自身传递给 Adapter 子类。 Adapter子类看起来像
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private final FragmentWithContextMenu fragment;
Adapter(FragmentWithContextMenu fragment) {
this.fragment = fragment;
}
@Override
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context)
.inflate(R.layout.child_view, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final Adapter.ViewHolder holder, int position) {
// Logic needed to bind holder to specific position
// ......
}
@Override
public int getItemCount() {
// Logic to return current item count
// ....
}
public class ViewHolder extends RecyclerView.ViewHolder implements ContextMenuHandler {
ViewHolder(View view) {
super(view);
((ViewWithContextMenu)view).setContextMenuHandler(fragment, this);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Do stuff to handle simple clicks on child views
// .......
}
});
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
// Logic to set up context menu goes here
// ....
}
@Override
public boolean onContextItemSelected(MenuItem item) {
// Logic to handle context menu item selections goes here
// ....
return true;
}
}
}
就是这样。这一切似乎都在起作用。它将所有实用程序类放在一个单独的 contextmenu 包中,因此我可以给出与子类匹配的类名称,但我认为会更混乱。