【问题标题】:Android view drag drop - accept view drop only if it matches certain view position?Android视图拖放 - 仅当它与特定视图位置匹配时才接受视图拖放?
【发布时间】:2015-08-08 15:51:18
【问题描述】:

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

我是个新手,到目前为止我能够实现拖放操作,但现在用户可以让视图在屏幕上的任何位置。

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

【问题讨论】:

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


    【解决方案1】:

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

    如我上面的说明性示例所示,有: 2 个具有两个相对布局(let1Container,let2Container)的图像视图(let1,let2) 此外,还有两个空白图像视图(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);
        }
    }
    

    现在让我们将未放置的图像发送回它的来源,为此我设法在onCreate() 跟踪 veiws 原始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();
    }
    

    请注意,包含的所有 sn-ps 都未经过测试,我只是在发布此答案时编写了它们。然而,这项技术对我来说很有吸引力,而且这段代码应该也能正常工作,我会让你尝试一下,如果需要,我很乐意提供任何帮助。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-19
      • 1970-01-01
      • 2011-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多