Reputation: 332
Hello every body I'm working on an android game that allows user to drag some views and place them above another.
I'm kinda newbie and so far i was able to achieve the drag and drop operation, but now the user is allowed to let the view any where in the screen.
All i want to do is to reset the view to its original location if it wasn't placed above any of the views that acts as a drop zone. please help.
Upvotes: 2
Views: 1706
Reputation: 332
This is pretty late! however I successfully accomplished it many days ago and now I have the time to share my solution in case any one is interested... I'll explain how I managed to do it on the following simplified example as my original code is pretty large to attach
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)
first we set the ontouchListener
for both letter views:
let1_ImageView.setOnTouchListener(this);
let2_ImageView.setOnTouchListener(this);
and then we make our activity implements View.OnTouchListener and provide an implementation of the method like the following :
@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;
}
the previous code allows the user to drag the letters to any where in the screen and calls a method I named as adjustLocation(view, X, Y);
once the dragged image is released at MotionEvent.ACTION_UP
this method will check if the dragged image is placed in one of the slots and in case it is not correctly placed it will put it back to its original location and here is how it works...
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);
}
}
now let us send the miss placed image back to where it came from, to do so I managed to keep track of veiws original LayoutParams
at onCreate()
let1_LayoutParams = (RelativeLayout.LayoutParams) let1.getLayoutParams();
let2_LayoutParams = (RelativeLayout.LayoutParams) let2.getLayoutParams();
and finally here is how we reset its location to the original location :
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();
}
Please be noted that all snippets included are not tested I just wrote them at the moment I was posting this answer. However the technique is working like charm to me and this code is supposed to work as well, I'll just leave you to try and I'll gladly offer any help if needed.
P.S. I don't know if this is really the best way to do it but I'm done waiting and wanted to move on, so any ideas to enhance the code or the technique will be more than appreciated.
Upvotes: 3