Android 视图拖放 - 仅在匹配特定视图位置时才接受视图拖放?

Android view drag drop - accept view drop only if it matches certain view position?

大家好,我正在开发一个 android 游戏,允许用户拖动一些视图并将它们放在另一个视图之上。

我有点新手,到目前为止我能够实现拖放操作,但现在允许用户在屏幕上的任何位置查看。

我想做的就是将视图重置到其原始位置(如果它没有放置在任何充当拖放区的视图之上)。请帮忙

来晚了!然而,我在很多天前就成功地完成了它,现在我有时间分享我的解决方案,以防有人感兴趣......我将在下面的简化示例中解释我是如何做到的,因为我的原始代码非常大附加

as indicated in my illustrative example above there are: 2 Image Views (let1, let2) with two Relative Layouts (let1Container, let2Container) Additionally there are two blank Image Views (slot1, slot2) that are intended to act as drop zones, along with their containers (slot1Container, slot2Container) of type (Relative Layout) All placed in RelativeLayout filling the screen and named (dragAreaRelativeLayout)

首先我们为两个字母视图设置 ontouchListener:

let1_ImageView.setOnTouchListener(this);
let2_ImageView.setOnTouchListener(this);

然后我们制作 activity 实现 View.OnTouchListener 并提供如下方法的实现:

@Override
public boolean onTouch(View view, MotionEvent event) {
    final int X = (int) event.getRawX();
    final int Y = (int) event.getRawY();

    ViewGroup parent = (ViewGroup) view.getParent();

    if (parent != null) {
        // detach the child from its parent
        parent.removeView(view);
    }

    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(view.getLayoutParams());


    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:


            layoutParams.leftMargin = X - 25;
            layoutParams.topMargin = Y - 25;
            layoutParams.rightMargin = -250;
            layoutParams.bottomMargin = -250;
            view.setLayoutParams(layoutParams);
            viewRootLayout.addView(view);

            break;
        case MotionEvent.ACTION_UP:

            adjustLocation(view, X, Y);

            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            break;
        case MotionEvent.ACTION_POINTER_UP:

            break;
        case MotionEvent.ACTION_MOVE:

            viewRootLayout = (ViewGroup) findViewById(R.id.dragAreaRelativeLayout);
            layoutParams.leftMargin = X - 25;
            layoutParams.topMargin = Y - 25;
            layoutParams.rightMargin = -250;
            layoutParams.bottomMargin = -250;
            view.setLayoutParams(layoutParams);
            viewRootLayout.addView(view);
            break;
    }
    viewRootLayout.invalidate();
    return true;
}

前面的代码允许用户将字母拖动到屏幕中的任何位置,并在 MotionEvent.ACTION_UP 释放拖动的图像后调用我命名为 adjustLocation(view, X, Y); 的方法,此方法将检查是否拖动的图像放置在其中一个插槽中,如果放置不正确,它将把它放回原来的位置,这是它的工作原理...

void adjustLocation(View view, int X, int Y) {
    RelativeLayout.LayoutParams slot1_LayoutParams = (RelativeLayout.LayoutParams) slot1.getLayoutParams();
    RelativeLayout.LayoutParams slot2_LayoutParams = (RelativeLayout.LayoutParams) slot2.getLayoutParams();
    int[] slot1_viewLocation = new int[2];
    int[] slot2_viewLocation = new int[2];
    slot1.getLocationInWindow(slot1_viewLocation);
    slot2.getLocationInWindow(slot1_viewLocation);

    //detect drop zone boundaries and check if the view is dropped at relative location
    if (Y >= slot1_viewLocation[1] && (Y < (slot1_viewLocation[1] + slot1.getHeight()))) {
        //first we check if it is placed over SLOT 1
        if ((X >= slot1_viewLocation[0]) && (X < (slot1_viewLocation[0] + slot1.getWidth()))) {
            view.setLayoutParams(slot1_LayoutParams);
            viewRootLayout = (ViewGroup) findViewById(R.id.slot1Container);
            viewRootLayout.addView(view);
        }
    } else if (Y >= slot2_viewLocation[1] && (Y < (slot2_viewLocation[1] + slot2.getHeight()))) {
        //then we check if it is placed over SLOT 2
        if ((X >= slot2_viewLocation[0]) && (X < (slot2_viewLocation[0] + slot2.getWidth()))) {
            view.setLayoutParams(slot2_LayoutParams);
            viewRootLayout = (ViewGroup) findViewById(R.id.let2SlotRelativeLayout);
            viewRootLayout.addView(view);
        }
    } else {
        // if the dragged image wasn't dropped neither in slot 1 or slot 2 (drop zaone 1,2)
        // we send it back to its location
        resetViewLocation(view);
    }
}

现在让我们将未放置的图像发送回它的来源,为此我设法在 onCreate()

跟踪原始 LayoutParams 的视图
let1_LayoutParams = (RelativeLayout.LayoutParams) let1.getLayoutParams();
let2_LayoutParams = (RelativeLayout.LayoutParams) let2.getLayoutParams();

最后是我们如何将其位置重置为原始位置:

void resetViewLocation(View view) {
    ViewGroup viewOriginalLayout = null;
    RelativeLayout.LayoutParams viewOriginalParams = null;
    ViewGroup parent = (ViewGroup) view.getParent();

    if (parent != null) {
        // detach the child from current parent
        parent.removeView(view);
    }

    int viewId = view.getId();

    if (viewId == let1.getId()) {
        viewOriginalParams = let1_LayoutParams;
        viewOriginalLayout = (ViewGroup) findViewById(R.id.let1Container);
    } else if (viewId == let2.getId()) {
        viewOriginalParams = let2_LayoutParams;
        viewOriginalLayout = (ViewGroup) findViewById(R.id.let2Container);
    }

    view.setLayoutParams(viewOriginalParams);
    viewOriginalLayout.addView(view);
    viewOriginalLayout.invalidate();
}

请注意,所有包含的片段都没有经过测试,我只是在发布此答案时写的。然而,这项技术对我来说很有魅力,这段代码应该也能正常工作,我会让你去尝试,如果需要,我很乐意提供任何帮助。

P.S。我不知道这是否真的是最好的方法,但我已经等不及了,想继续前进,所以任何增强代码或技术的想法都将不胜感激。