Android视图拖放 - 只有在匹配特定视图位置时才接受视图丢弃?

时间:2015-08-08 15:51:19

标签: android android-layout drag-and-drop android-relativelayout

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

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

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

1 个答案:

答案 0 :(得分:2)

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

enter image description here

  
    

如上面的说明性示例中所示,有:     2图像视图(let1,let2),带有两个相对布局(let1Container,let2Container)     此外,还有两个空白图像视图(slot1,slot2),用作拖放区,以及类型(相对布局)的容器(slot1Container,slot2Container)     所有放在RelativeLayout中的填充屏幕并命名为(dragAreaRelativeLayout)

  

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

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

然后我们让我们的活动实现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;
}

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

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

现在让我们将未命中的图像发送回原来的位置,为此我设法跟踪LayoutParams

上的原始onCreate()的视频
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。我不知道这是否真的是最好的方式,但我已经等待并希望继续前进,所以任何增强代码或技术的想法都将得到更多的赞赏。