I'm trying to drag and drop multiple items.
Currently I have one set of Imagebuttons defined in a Linear layout, and another defined in a separate linear layout.
I'd like to make it so if you drag from a button that is not at the bottom of the layout, it will drag all items below it along with it.
With the stock drag and drop code (below) it only allows me to drag one.
private final class MyTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
}
else {
return false;
}
}
}
I think I might be able to move more than one view through here, but I honestly don't know that much about them.
The drag and drop area (minus my log code and whatnot) looks typical:
class MyDragListener implements View.OnDragListener {
//Drawable enterShape = getResources().getDrawable(R.drawable.shape_droptarget);
//Drawable normalShape = getResources().getDrawable(R.drawable.shape);
#Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
View view = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) view.getParent();
LinearLayout container = (LinearLayout) v;
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// do nothing
break;
case DragEvent.ACTION_DRAG_ENTERED:
//v.setBackgroundDrawable(enterShape);
break;
case DragEvent.ACTION_DRAG_EXITED:
//v.setBackgroundDrawable(normalShape);
break;
case DragEvent.ACTION_DROP:
// Dropped, reassign View to ViewGroup
owner.removeView(view);
container.addView(view);
view.setVisibility(View.VISIBLE);
break;
case DragEvent.ACTION_DRAG_ENDED:
//rebuildField(); works well but is clogging up the logs
//v.setBackgroundDrawable(normalShape);
default:
break;
}
return true;
}
}
I ended up solving this by finding out a lot about views, inflaters, and layouts.
I wrote a function that finds all the ImageButtons below where the user clicked, and set them all to invisible. I then created a new Linear Layout within the Linear Layout that the user clicked, and passed that into the Drag Shadow builder.
Once into the ACTION_DROP portion, I simply referenced global variables to figure out if the user dropped in one or multiple ImageButtons, and dealt with them accordingly.
Related
I am using OnDragListener to drag and drop image. i have MOTIONEVENT.ACTION_MOVE to implement image moving functionality. At a certain point in the action move, I want to end the drag and remove its shadow. Is it possible to set the action in drag event? Before releasing finger i want to call drop event.
switch(event.getAction()) {
case MotionEvent.ACTION_MOVE:
//here i want to remove shadow and stop dragging
break;
case DragEvent.ACTION_DROP:break;
}
You can implement OnDragListener in your class/ fragments.
class MyDrag implements OnDragListener {
Drawable image = getResources().getDrawable(
R.drawable.shape_droptarget);
#Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// Signals the start of a drag and drop operation
break;
case DragEvent.ACTION_DRAG_ENTERED:
//Signals to a View that the drag point has entered the bounding box of the View
v.setBackgroundDrawable(image);
break;
case DragEvent.ACTION_DRAG_EXITED:
//Signals that the user has moved the drag shadow out of the bounding box of the View or into a descendant view that can accept the data.
v.setBackgroundDrawable(image);
break;
case DragEvent.ACTION_DROP:
// Signals to a View that the user has released the drag shadow, and the drag point is within the bounding box of the View and not within a descendant view that can accept the data.
View view = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) view.getParent();
owner.removeView(view);
LinearLayout container = (LinearLayout) v;
container.addView(view);
view.setVisibility(View.VISIBLE);
break;
case DragEvent.ACTION_DRAG_ENDED:
//Signals to a View that the drag and drop operation has concluded.
v.setBackgroundDrawable(image);
default:
break;
}
return true;
}
}
for more details refer here Drag and Drop
I have a project which i'm required to develop Android game that display a 5*5 table and and image for each player which each one of them can move the image in place inside the 5*5 table.
ex:
Note : I need to know the exact coordinates (or anything relative) so i can save the position in array and move the image to that new place (eg : re-draw it on the new position).
Any ideas ?
Thanks in advance.
Just use a RelativeLayout with 5x5 ImageViews (set to not visible).
And on the images that the user can move to the place, use Drag and Drop.
In onDrag you set the visibility of the image to Gone.
For all ImageView (5x5 Table), you set the onDragListener.
After that, in the overwritten method OnDrop, you can receive the view that is dropped and can determine which drawable to show.
edit:
Oh well, in this case I would use GridView as said in the comments. And make usage of drag and drop. You don't need to attach a DragListener to every image then. You can simply let the GridView listen to the drop events and determine by the x and y where to drop.
Little example (just as a hint)
gameStoneView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
DragShadowBuilder shadowBuilder = new DragShadowBuilder(gameStoneView);
gameStoneView.startDrag(null, shadowBuilder, gameStoneView, 0);
if (dragListener != null) {
dragListener.onDragStart();
}
break;
default:
LOG.v("Motion event reorderIcon: DEFAULT - not action down");
}
return true;
}
});
gridView.setOnDragListener(new OnDragListener() {
#Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_LOCATION:
currentY = event.getY();
currentX = event.getX();
break;
case DragEvent.ACTION_DROP:
final Point position = getPositionOfItem(currentX, currentY);
dropItemAt(position);
break;
case DragEvent.ACTION_DRAG_EXITED:
//BORDER DRAGEVENT: ACTION_DRAG_EXITED
viewDraggedOutSide = true;
break;
case DragEvent.ACTION_DRAG_ENDED:
//BORDER DRAGEVENT: ACTION_DRAG_ENDED
if (viewDraggedOutSideList) {
reinsertDraggedItem();
update();
}
viewDraggedOutSideList = false;
return true;
default:
return true;
}
}
});
I am making an game application where i need to use onDraglistener for drag and drop here what I am doing on a class which implements onDraglistener.
#Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
Log.v("here","drag started");
//no action necessary
break;
case DragEvent.ACTION_DRAG_ENTERED:
//no action necessary
Log.v("here","drag enteres");
break;
case DragEvent.ACTION_DRAG_LOCATION:
int mCurX = (int) event.getX();
int mCurY = (int) event.getY();
Log.v("Cur(X, Y) : " ,"here ::" + mCurX + ", " + mCurY );
break;
case DragEvent.ACTION_DRAG_EXITED:
//no action necessary
Log.v("here","drag exits");
break;
case DragEvent.ACTION_DROP:
.................do what ever when dropped...
}
here what I am doing on touchlistener of a view to be dragged and dropped:
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
/*
* Drag details: we only need default behavior
* - clip data could be set to pass data as part of drag
* - shadow can be tailored
*/
view.setTag("option"+index);
ClipData data = ClipData.newPlainText("tag", "option"+index);
shadowBuilder = new View.DragShadowBuilder(view);
//start dragging the item touched
view.startDrag(data, shadowBuilder, view, 0);
offsetX = (int)view.getX();//(int)motionEvent.getX();
offsetY = (int)view.getY();//motionEvent.getY();
Log.v("here","it is ::" + (int)motionEvent.getX() + " , "+(int)motionEvent.getY());
return false;
}
Now it builds the shadow builder which gest dragged to anywhere you drag finger.
How could I animate the shadow builder or the view going back to its position when not dropped to target?
I tried public boolean onInterceptTouchEvent(MotionEvent event) and moving to parent view and taking x,y position and animating it to go back to its original position but it gets action cancelled.
Is there any way to get x,y coordinates to a place the view dropped other then the target. Then I would be able to animate it between the positions.
You need to handle the drop:
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_ENTERED:
//break here was removed in purpose so you can see the shadow and the element is still at its initial place.
case DragEvent.ACTION_DROP:
View view = (View) event.getLocalState();
if (prioritiesList.contains(v)) {
ViewGroup viewgroup = (ViewGroup) view.getParent();
viewgroup.removeView(view);
LinearLayout containView = (LinearLayout) v;
containView.addView(view);
view.setVisibility(View.VISIBLE);
break;
}
I am making a small application on android, it is based on dragdrop with shadowbuilder, i used an emulator with screen wvga800 (800x480), it was working fine, when draging an element to a grid it drops properly in the destination grid.
Then i used another emulator with screen wxga800-7in (1280-800), it went all wrong,
the elements dont drop anymore inside the grid, they appear to shift to another position.
note: in the layout XML file the used unit is dp.
What is excactly the problem here? please help.
Thanks in advance for any help.
The following are the code for touch listener and drag listener :
private final class MyTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view,0);
view.setVisibility(View.INVISIBLE);
return true;}
else {
return false;
}
}
}//class MyTouchListener
class MyDragListener implements View.OnDragListener {
Drawable enterShapeAcp = getResources().getDrawable(R.drawable.shape_droptargetacp);
Drawable enterShapeRej= getResources().getDrawable(R.drawable.shape_droptargetrej);
Drawable normalShape = getResources().getDrawable(R.drawable.shape);
#Override
public boolean onDrag(View v, DragEvent event) {
// int action = event.getAction();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:{
break;}
case DragEvent.ACTION_DRAG_ENTERED:{
grid(v.getX(),v.getY());
v.setBackgroundDrawable(enterShapeAcp);
break;}
case DragEvent.ACTION_DRAG_EXITED:{
v.setBackgroundDrawable(normalShape);
break;}
case DragEvent.ACTION_DROP:{
View view = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) view.getParent();
owner.removeView(view);
LinearLayout container = (LinearLayout) v;
container.addView(view);
view.setVisibility(View.VISIBLE);
break;}
case DragEvent.ACTION_DRAG_ENDED:{
v.setBackgroundDrawable(normalShape);
break;}
default:{
break;}
}//switch
return true;
}//onDrag
}//class MyDragListener
Are you sure the LinearLayout has proper Orientation? If not it may scale unexpectedly and provide weird results.
EDIT: If you are familiar with debugging it will help you a lot to understand which grid element is receiving the view and what went wrong. Give some time to it with both emulators and figure out the difference.
How can I listen the move events after the LongPress is caled in my GestureDetector?
When the user LongClick he starts the selection mode, and can drag a square into the screen. But I noticed that the onScroll is not called after LongPress is consumed.
Tried to do fight this for a while, and for now the solution is:
Disable the longpress using setIsLongpressEnabled(isLongpressEnabled) on your gestureDetector
Here is my OnTouch method of my View:
public boolean onTouchEvent(MotionEvent event) {
if (mGestureDetector.onTouchEvent(event)== true)
{
//Fling or other gesture detected (not logpress because it is disabled)
}
else
{
//Manually handle the event.
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
//Remember the time and press position
Log.e("test","Action down");
}
if (event.getAction() == MotionEvent.ACTION_MOVE)
{
//Check if user is actually longpressing, not slow-moving
// if current position differs much then press positon then discard whole thing
// If position change is minimal then after 0.5s that is a longpress. You can now process your other gestures
Log.e("test","Action move");
}
if (event.getAction() == MotionEvent.ACTION_UP)
{
//Get the time and position and check what that was :)
Log.e("test","Action down");
}
}
return true;
}
My device returned ACTION_MOVE whenever I hold finger on the screen. If your doesnt, just check the state of some pressed flag after 0.5s using a timer or thread.
Hope that helps!
I have done this task by using the following concepts:
Suppose I have the Image View and on long press on it, image inside this image View would be drag-able and placed inside the another view(e.g. Relative Layout)
Set MyClickListner on Image View's setOnLongClickListener() method.
private final class MyClickListener implements View.OnLongClickListener {
// called when the item is long-clicked
#Override
public boolean onLongClick(View view) {
// TODO Auto-generated method stub
// create it from the object's tag
ClipData.Item item = new ClipData.Item((CharSequence)view.getTag());
String[] mimeTypes = { ClipDescription.MIMETYPE_TEXT_PLAIN };
ClipData data = new ClipData(view.getTag().toString(), mimeTypes, item);
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag( data, //data to be dragged
shadowBuilder, //drag shadow
view, //local data about the drag and drop operation
0 //no needed flags
);
// view.setVisibility(View.INVISIBLE);
return true;
}
}
Then set MyDragListner on Relative Layout(e.g. bigImageRelativeLayoutVw.setOnDragListener(new MyDragListener());)
class MyDragListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
int X=(int)event.getX();
int Y=(int)event.getY();
int touchX = 0,touchY=0;
// Handles each of the expected events
switch (event.getAction()) {
//signal for the start of a drag and drop operation.
case DragEvent.ACTION_DRAG_STARTED:
// do nothing
break;
//the drag point has entered the bounding box of the View
case DragEvent.ACTION_DRAG_ENTERED:
break;
//the user has moved the drag shadow outside the bounding box of the View
case DragEvent.ACTION_DRAG_EXITED:
// v.setBackground(normalShape); //change the shape of the view back to normal
break;
//drag shadow has been released,the drag point is within the bounding box of the View
case DragEvent.ACTION_DROP:
// if the view is the bottomlinear, we accept the drag item
if(v == bigImageRelativeLayoutVw) {
View view = (View) event.getLocalState();
touchX=X-viewCoords[0]-20;
touchY=Y-viewCoords[1]-20;
View view1=new View(getActivity());
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(30,30);
layoutParams.leftMargin =touchX;
layoutParams.topMargin = touchY;
view1.setBackgroundResource(R.drawable.heavy_damage);
view1.setLayoutParams(layoutParams);
RelativeLayout containView = (RelativeLayout) v;
containView.addView(view1);
view.setVisibility(View.VISIBLE);
} else {
View view = (View) event.getLocalState();
view.setVisibility(View.VISIBLE);
break;
}
break;
//the drag and drop operation has concluded.
case DragEvent.ACTION_DRAG_ENDED:
// v.setBackground(normalShape); //go back to normal shape
default:
break;
}
return true;
}
}