我正在尝试使用带有垂直LinearLayoutManager的RecyclerView来显示列表项。此列表可以包含多种不同的项类型(不同的布局),并且可以由用户使用拖放进行重新排序。
对于项目类型,如Android文档中所述,我已重写getItemType方法,以便在回收器中处理不同类型的视图,并在onCreateViewHolder和onBindViewHolder中处理它。这就像一个魅力。
对于拖放重新排序,我使用了ItemTouchHelper.Callback(受this sample project启发)。这也很有效。
当我尝试使用不同的项类型和拖放行为时,会出现问题。只要在相同类型的项之间发生拖动,这就可以正常工作,但是当我在类型B的视图上拖动类型A的视图时,拖动停止并且视图返回到它的原始位置。
这是我的代码:
MyFragment.java
public class MyFragment extends Fragment implements MyAdapter.Listener {
private MyViewModel mViewModel;
private RecyclerView mRecyclerView;
private MyAdapter mAdapter;
private ItemTouchHelper mItemTouchHelper;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment, container, false);
mRecyclerView = root.findViewById(R.id.recyclerView);
mAdapter = new MyAdapter(this);
mRecyclerView.setAdapter(mAdapter);
mItemTouchHelper = new ItemTouchHelper(new MyDragHelperCallback(mAdapter));
mItemTouchHelper.attachToRecyclerView(mRecyclerView);
mViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);
mViewModel.addObserver(this, new Observer<List<Item>>() {
@Override
public void onChanged(@Nullable List<Item> items) {
mAdapter.updateList(items);
}
});
mAdapter.updateList(mViewModel.getList());
return root;
}
@Override
public void onStartDragRequest(@NonNull RecyclerView.ViewHolder viewHolder) {
mItemTouchHelper.startDrag(viewHolder);
}
}
MyDragHelperCallback.java
public class MyDragHelperCallback extends ItemTouchHelper.Callback {
private static final int DRAG_MOVEMENT_FLAGS = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
@NonNull
private MyDragListener mListener;
public MyDragHelperCallback(@NonNull MyDragListener listener) {
mListener = listener;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (!(recyclerView.getLayoutManager() instanceof LinearLayoutManager)) {
throw new IllegalArgumentException("Should only be used with a LinearLayoutManager");
}
return makeMovementFlags(DRAG_MOVEMENT_FLAGS, 0);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mListener.onItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// Nothing to do
}
}
MyDragListener.java
public interface MyDragListener {
void onItemMoved(int from, int to);
}
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyHolder> implements MyDragListener {
@Nullable
private List<Item> mList;
public void updateList(@Nullable List<Item> list) {
mList = list;
notifyDataSetChanged();
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
return new MyHolderBis(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bis, parent, false));
}
return new MyHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
}
@Override
public void onBindViewHolder(final MyHolder holder, int position) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mListener.onStartDragRequest(holder);
return true;
}
});
// bind views to data
}
@Override
public int getItemCount() {
return mList != null ? mList.size() : 0;
}
@Override
public int getItemViewType(int position) {
return mList.get(position).getType();
}
@Override
public void onItemMoved(int from, int to) {
notifyItemMoved(from, to);
}
}
我有遗漏的东西吗? 或者这是否有可能实现?
感谢您的所有答案!