RecyclerView拖放不适用于多种视图类型

时间:2017-11-28 17:48:10

标签: java android android-recyclerview drag-and-drop itemtouchhelper

我正在尝试使用带有垂直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);
    }
}

我有遗漏的东西吗? 或者这是否有可能实现?

感谢您的所有答案!

0 个答案:

没有答案