将 Listview 项目拖放到另一个项目中

Drag drop Listview item into another item

我有一个包含不同项目类型的列表视图:header,文件夹和文件如下:

现在我想实现拖动文件项并将其放入文件夹项并获取源和目标 position.I不想像某些拖动排序那样在拖动时更改目标位置(重新排列)列表视图库。

有什么建议可以入手吗?

将您的 ListView 切换为 RecyclerView 将使事情变得容易得多。

您可以在 Styling Android and the whole code here.

上找到整篇文章

此代码使用 OnItemTouchListener 来检测何时应拖动项目。在 RecyclerView 上方有一个 ImageView,其中包含正在移动的项目图像以廉价地对其进行动画处理。

OnItemTouckListener (DragController.java):

public class DragController implements RecyclerView.OnItemTouchListener {
    private RecyclerView recyclerView;
    private ImageView overlay;
    private final GestureDetectorCompat gestureDetector;

    private boolean isDragging = false;

    public DragController(RecyclerView recyclerView, ImageView overlay) {
        this.recyclerView = recyclerView;
        this.overlay = overlay;
        GestureDetector.SimpleOnGestureListener longClickGestureListener = new GestureDetector.SimpleOnGestureListener() {
            @Override
            public void onLongPress(MotionEvent e) {
                super.onLongPress(e);
                isDragging = true;
                dragStart(e.getX(), e.getY());
            }
        };
        this.gestureDetector = new GestureDetectorCompat(recyclerView.getContext(), longClickGestureListener);
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        if (isDragging) {
            return true;
        }
        gestureDetector.onTouchEvent(e);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        int x = (int) e.getX();
        int y = (int) e.getY();
        View view = recyclerView.findChildViewUnder(x, y);
        if (e.getAction() == MotionEvent.ACTION_UP) {
            dragEnd(view);
            isDragging = false;
        } else {
            drag(y, view);
        }
    }

开始和结束拖动(DragController.java):

private boolean isFirst = true;
private static final int ANIMATION_DURATION = 100;
private int draggingItem = -1;
private float startY = 0f;
private Rect startBounds = null;

private void dragStart(float x, float y) {
    View draggingView = recyclerView.findChildViewUnder(x, y);
    View first = recyclerView.getChildAt(0);
    isFirst = draggingView == first;
    startY = (y - draggingView.getTop());
    paintViewToOverlay(draggingView);
    overlay.setTranslationY(y - startY);
    draggingView.setVisibility(View.INVISIBLE);
    draggingItem = recyclerView.indexOfChild(draggingView);
    startBounds = new Rect(draggingView.getLeft(), draggingView.getTop(), draggingView.getRight(), draggingView.getBottom());
}

private void drag(int y, View view) {
    overlay.setTranslationY(y - startY);
}

private void dragEnd(View view) {
    overlay.setImageBitmap(null);
    view.setVisibility(View.VISIBLE);
    view.setTranslationY(overlay.getTranslationY() - view.getTop());
    view.animate().translationY(0f).setDuration(ANIMATION_DURATION).start();
}

private void paintViewToOverlay(View view) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);
    overlay.setImageBitmap(bitmap);
    overlay.setTop(0);
}

代码是Mark Allison on StylingAndroid.

写的

编辑:

But I don't know how to get the position of item when dragging is end

答案位于 part 7 样式 Android。

View view = recyclerView.findChildViewUnder(0, y);

And how can I disable drag on Folder and Header item? Just allow dragging File item?

您可以使用多个 ViewType(文件、文件夹和 header)来执行此操作。然后你可以在DragController中使用getItemViewType只对文件开始移动。

使用RecyclerViewItemTouchHelper.SimpleCallback

您可以在 activity:

中这样设置
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list); // Your layout with RecyclerView

    RecyclerView itemRecyclerView = findViewById(R.id.itemRecyclerView);

    LinearLayoutManager itemLayoutManager = new LinearLayoutManager(this);
    itemRecyclerView.setLayoutManager(itemLayoutManager);

    itemAdapter = new ItemAdapter(); // Your adapter which extends RecyclerView.Adapter

    itemRecyclerView.setAdapter(itemAdapter);
    itemRecyclerView.setHasFixedSize(true);

    itemDragAndDropCallback = new ItemDragAndDropCallback(this, itemRecyclerView);
    // Your class which extends ItemTouchHelper.SimpleCallback
    // It will be shown in the next code sample

    new ItemTouchHelper(itemDragAndDropCallback)
        .attachToRecyclerView(itemRecyclerView);
}

您可以使用 ItemTouchHelper.SimpleCallback 提供的项目拖动的默认功能。 以下class 将演示更改文件夹的背景颜色。项目将被放入该文件夹。

class ItemDragAndDropCallback extends ItemTouchHelper.SimpleCallback {

    ItemDragAndDropCallback() {
        // Choose drag and swipe directions
        // Up and down is chosen for dragging
        // Right and left is chosen for swiping
        super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        // You can reorder items here
        // Do nothing in your case
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        // You can react for swiping items here
        // Do nothing in your case
    }

    // An item will be dropped into this folder
    private View folder;

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        super.onSelectedChanged(viewHolder, actionState);

        if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {

            // Here you are notified that the drag operation began

            if (folder != null) {
                folder.setBackgroundResource(0); // Clear former folder background
            }
        } else if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {

            // Here you are notified that the last operation ended

            if (folder != null) {
                // Set folder background to a color indicating
                // that an item was dropped into it
                folder.setBackgroundColor(
                    ContextCompat.getColor(
                        recyclerView.getContext(), android.R.color.holo_green_dark
                    )
                );
            }
        }
    }

    @Override
    public void onChildDraw(
        Canvas c,
        RecyclerView recyclerView,
        RecyclerView.ViewHolder viewHolder,
        float dX,
        float dY,
        int actionState,
        boolean isCurrentlyActive
    ) {
        if (actionState == ItemTouchHelper.ACTION_STATE_DRAG && isCurrentlyActive) {

            // Here you are notified that the drag operation is in progress

            if (folder != null) {
                folder.setBackgroundResource(0); // Clear former folder background
            }

            float itemActualPosition = viewHolder.itemView.getTop() + dY;

            // Find folder under dragged item
            for (int i = 0; i < recyclerView.getChildCount(); i++) {
                folder = recyclerView.getChildAt(i);

                // Exclude dragged item from detection
                if (!folder.equals(viewHolder.itemView)) {

                    // Accept folder which encloses item position
                    if (folder.getTop() < itemActualPosition && itemActualPosition < folder.getBottom()) {

                        // Set folder background to a color indicating
                        // that an item will be dropped into it upon release
                        folder.setBackgroundColor(
                            ContextCompat.getColor(
                                recyclerView.getContext(), android.R.color.holo_green_light
                            )
                        );
                        break;
                    }
                }
            }
        }
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }
}

当您将项目拖到文件夹上时,项目下方的文件夹背景将为浅绿色。 当您将项目放入文件夹时,其背景将为深绿色。