Image dragging and dropping

半城伤御伤魂 提交于 2019-12-22 17:49:21

问题


I have started the previous question, but I want to change the method of dragging.

So the task is, the user (kid) learns how to do addition. So there's 2 candies, and 1 candy jar. The user requires to drag and drop the candy to the jar. How to do it?

These is the code I have:

Main xml

<?xml version="1.0" encoding="utf-8"?>


<AbsoluteLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mainLayout">
<ImageView android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/emptyLetterView" android:src="@drawable/r_empty" android:layout_x="200px" android:layout_y="300px"></ImageView>
<ImageView android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/letterView" android:src="@drawable/r_filled" ></ImageView>
</AbsoluteLayout>

This is the java file package edu.sbcc.cs123.draganddropbasic;

import android.app.*;
import android.graphics.*;
import android.os.*;
import android.view.*;
import android.view.View.*;
import android.widget.*;

@SuppressWarnings("deprecation")
public class DragAndDropBasicActivity extends Activity implements OnTouchListener {
    private ImageView letterView;                       // The letter that the user drags.
    private ImageView emptyLetterView;              // The letter outline that the user is supposed to drag letterView to.
    private AbsoluteLayout mainLayout;


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mainLayout = (AbsoluteLayout) findViewById(R.id.mainLayout);
        mainLayout.setOnTouchListener(this);
        letterView = (ImageView) findViewById(R.id.letterView);
        letterView.setOnTouchListener(this);

        emptyLetterView = (ImageView) findViewById(R.id.emptyLetterView);
    }

    private boolean dragging = false;
    private Rect hitRect = new Rect();

    @Override
    /**
     * NOTE:  Had significant problems when I tried to react to ACTION_MOVE on letterView.   Kept getting alternating (X,Y) 
     * locations of the motion events, which caused the letter to flicker and move back and forth.  The only solution I could 
     * find was to determine when the user had touched down on the letter, then process moves in the ACTION_MOVE 
     * associated with the mainLayout.
     */
    public boolean onTouch(View v, MotionEvent event) {
        boolean eventConsumed = true;
        int x = (int)event.getX();
        int y = (int)event.getY();

        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            if (v == letterView) {
                dragging = true;
                eventConsumed = false;
            }
        } else if (action == MotionEvent.ACTION_UP) {

            if (dragging) {
                emptyLetterView.getHitRect(hitRect);
                if (hitRect.contains(x, y))
                    setSameAbsoluteLocation(letterView, emptyLetterView);
            }
            dragging = false;
            eventConsumed = false;

        } else if (action == MotionEvent.ACTION_MOVE) {
            if (v != letterView) {
                if (dragging) {
                    setAbsoluteLocationCentered(letterView, x, y);
                }
            }
        }

        return eventConsumed;

    }


    private void setSameAbsoluteLocation(View v1, View v2) {
        AbsoluteLayout.LayoutParams alp2 = (AbsoluteLayout.LayoutParams) v2.getLayoutParams();
        setAbsoluteLocation(v1, alp2.x, alp2.y);
    }


    private void setAbsoluteLocationCentered(View v, int x, int y) {
        setAbsoluteLocation(v, x - v.getWidth() / 2, y - v.getHeight() / 2);
    }


    private void setAbsoluteLocation(View v, int x, int y) {
        AbsoluteLayout.LayoutParams alp = (AbsoluteLayout.LayoutParams) v.getLayoutParams();
        alp.x = x;
        alp.y = y;
        v.setLayoutParams(alp);
    }
}

And this is what I have been implementing for awhile I just add the new variables and change it to letterView1 and emptyLetterView1

Java file:

package edu.sbcc.cs123.draganddropbasic;

import android.app.*;
import android.graphics.*;
import android.os.*;
import android.view.*;
import android.view.View.*;
import android.widget.*;

@SuppressWarnings("deprecation")
public class DragAndDropBasicActivity extends Activity implements OnTouchListener {
    private ImageView letterView;                       // The letter that the user drags.
    private ImageView emptyLetterView;          // The letter outline that the user is supposed to drag letterView to.
    private ImageView letterView1;                      // The letter that the user drags.
    private ImageView emptyLetterView1; 
    private AbsoluteLayout mainLayout;


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mainLayout = (AbsoluteLayout) findViewById(R.id.mainLayout);
        mainLayout.setOnTouchListener(this);
        letterView = (ImageView) findViewById(R.id.letterView);
        letterView.setOnTouchListener(this);

        emptyLetterView = (ImageView) findViewById(R.id.emptyLetterView);

        letterView1 = (ImageView) findViewById(R.id.letterView1);
        letterView1.setOnTouchListener(this);

        emptyLetterView1 = (ImageView) findViewById(R.id.emptyLetterView1);
    }

    private boolean dragging = false;
    private Rect hitRect = new Rect();

    @Override
    /**
     * NOTE:  Had significant problems when I tried to react to ACTION_MOVE on letterView.   Kept getting alternating (X,Y) 
     * locations of the motion events, which caused the letter to flicker and move back and forth.  The only solution I could 
     * find was to determine when the user had touched down on the letter, then process moves in the ACTION_MOVE 
     * associated with the mainLayout.
     */
    public boolean onTouch(View v, MotionEvent event) {
        boolean eventConsumed = true;
        int x = (int)event.getX();
        int y = (int)event.getY();

        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            if (v == letterView) {
                dragging = true;
                eventConsumed = false;
            }
            if (v == letterView1) {
                dragging = true;
                eventConsumed = false;
            }
        } else if (action == MotionEvent.ACTION_UP) {

            if (dragging) {
                emptyLetterView.getHitRect(hitRect);
                if (hitRect.contains(x, y))
                    setSameAbsoluteLocation(letterView, emptyLetterView);
            }

            if (dragging) {
                emptyLetterView1.getHitRect(hitRect);
                if (hitRect.contains(x, y))
                    setSameAbsoluteLocation1(letterView1, emptyLetterView1);
            }
            dragging = false;
            eventConsumed = true;

        } else if (action == MotionEvent.ACTION_MOVE) {
            if (v != letterView) {
                if (dragging) {
                    setAbsoluteLocationCentered(letterView, x, y);
                }
            }
            if (v != letterView1) {
                if (dragging) {
                    setAbsoluteLocationCentered1(letterView1, x, y);
                }
            }
        }

        return eventConsumed;

    }


    private void setSameAbsoluteLocation(View v1, View v2) {
        AbsoluteLayout.LayoutParams alp2 = (AbsoluteLayout.LayoutParams) v2.getLayoutParams();
        setAbsoluteLocation(v1, alp2.x, alp2.y);
    }


    private void setAbsoluteLocationCentered(View v, int x, int y) {
        setAbsoluteLocation(v, x - v.getWidth() / 2, y - v.getHeight() / 2);
    }


    private void setAbsoluteLocation(View v, int x, int y) {
        AbsoluteLayout.LayoutParams alp = (AbsoluteLayout.LayoutParams) v.getLayoutParams();
        alp.x = x;
        alp.y = y;
        v.setLayoutParams(alp);
    }




    private void setSameAbsoluteLocation1(View v1, View v2) {
        AbsoluteLayout.LayoutParams alp2 = (AbsoluteLayout.LayoutParams) v2.getLayoutParams();
        setAbsoluteLocation1(v1, alp2.x, alp2.y);
    }


    private void setAbsoluteLocationCentered1(View v, int x, int y) {
        setAbsoluteLocation1(v, x - v.getWidth() / 2, y - v.getHeight() / 2);
    }


    private void setAbsoluteLocation1(View v, int x, int y) {
        AbsoluteLayout.LayoutParams alp = (AbsoluteLayout.LayoutParams) v.getLayoutParams();
        alp.x = x;
        alp.y = y;
        v.setLayoutParams(alp);
    }
}

I have added the image file to the xml file and change the id to letterView1 and emptyLetterView1 as well.

So another image is shown successfully, however, when I dragged one of the image, another images disappeared.

How can I implement this please?


回答1:


The issue with your code is here

else if (action == MotionEvent.ACTION_MOVE) {
        if (v != letterView) {
            if (dragging) {
                setAbsoluteLocationCentered(letterView, x, y);
            }
        }
        if (v != letterView1) {
            if (dragging) {
                setAbsoluteLocationCentered1(letterView1, x, y);
            }
        }
    }

Now in your earlier code there were 2 listeners.

  1. The main background
  2. The letterView

Now you have 3 listeners so if (v != letterView) will be true if the user is dragging on the ground or on the letter.

For example if you start dragging on a random patch of screen then v!=letterView and v!=letterView1. They will both be centered then to the same point so one will APPEAR to have hidden.

Same will hold true if you drag on one of them. The other will move to that point and it will appear hidden.

Instead of using non-equations you can try

else if (action == MotionEvent.ACTION_MOVE) {
        if (v == letterView) {
            if (dragging) {
                setAbsoluteLocationCentered(letterView, x, y);
            }
        }
        if (v == letterView1) {
            if (dragging) {
                setAbsoluteLocationCentered1(letterView1, x, y);
            }
        }
    }

Or you can even do a hit test

   else if (action == MotionEvent.ACTION_MOVE) {
        letterView.getHitRect(hitRect);
        if (letterView.contains(x,y)) {
            if (dragging) {
                setAbsoluteLocationCentered(letterView, x, y);
            }
        }
        letterView1.getHitRect(hitRect);
        if (letterView1.contains(x,y)) {
            if (dragging) {
                setAbsoluteLocationCentered1(letterView1, x, y);
            }
        }
  }



回答2:


I would base your solution on following code/information:

  • Drag and Drop official guide
  • Samples from SDk: DragAndDrop & DragableDot
  • Vogella's tutorial on Drag and Drop
  • Three part blog post about Drag and Drop 1,2 and 3


来源:https://stackoverflow.com/questions/14291752/image-dragging-and-dropping

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!