简体   繁体   English

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

[英]Drag drop Listview item into another item

I have a list view with different item types: header, folder and file like this: 我有一个列表视图与不同的项目类型:标题,文件夹和文件,如下所示:

在此输入图像描述

Now I 'd like to implement drag file item and drop it into folder item and get the source and target position.I don't want to change the target position (rearrange) while dragging like some drag sort list view libraries. 现在我想实现拖动文件项并将其放入文件夹项并获取源和目标位置。我不想像拖动排序列表视图库那样拖动时更改目标位置(重新排列)。

Is there any suggestion to start with? 有什么建议可以开始吗?

Switching your ListView to RecyclerView will make things a lot easier. ListView切换到RecyclerView将使事情变得更容易。

You can find the whole article on Styling Android and the whole code here. 你可以在这里找到关于Styling Android和整个代码的整篇文章

This code uses OnItemTouchListener to detect when an item should be dragged. 此代码使用OnItemTouchListener来检测何时应该拖动项目。 There is an ImageView above the RecyclerView with an image of the item being moved to cheaply animate it. RecyclerView上方有一个ImageView ,其中的项目图像被移动到便宜的动画。

The OnItemTouckListener ( DragController.java ): OnItemTouckListenerDragController.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);
        }
    }

Starting and ending the drag ( DragController.java ): 开始和结束拖动( 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);
}

The code is written by Mark Allison on StylingAndroid. 代码由Mark Allison在StylingAndroid上编写。

Edit: 编辑:

But I don't know how to get the position of item when dragging is end 但是当拖动结束时我不知道如何获得项目的位置

The answer is located in part 7 on Styling Android. 答案位于Styling Android的第7部分

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

And how can I disable drag on Folder and Header item? 如何禁用文件夹和标题项上的拖动? Just allow dragging File item? 只是允许拖动文件项?

You can do this by using multiple ViewTypes (file, folder & header). 您可以使用多个ViewTypes(文件,文件夹和标题)来完成此操作。 Then you can use getItemViewType in DragController to start the movement only for files. 然后,您可以在DragController使用getItemViewType来仅为文件启动移动。

Use RecyclerView and ItemTouchHelper.SimpleCallback . 使用RecyclerViewItemTouchHelper.SimpleCallback

You can setup it like that in your 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);
}

You can use default functionality for item dragging provided by ItemTouchHelper.SimpleCallback . 您可以使用ItemTouchHelper.SimpleCallback提供的项拖动的默认功能。 The following class will demonstrate changing the background color of a folder. 以下类将演示如何更改文件夹的背景颜色。 An item will be dropped into that folder. 项目将被放入该文件夹中。

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);
    }
}

When you drag an item over folders then the folder's background under the item will be light green. 将项目拖到文件夹上时,项目下的文件夹背景将显示为浅绿色。 When you drop the item into a folder then its background will be dark green. 将项目放入文件夹时,其背景将为深绿色。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM