I use android's drag&drop functionallity to move some imageviews into another imageview. This allows to make a selection depending on what imageview I dropped into the destiny imageview.
But now I have to consider that the user could make a mistake when selecting, and need to have some kind of reset button, which would return these imageview's to their original place and cancel the drag&drop.
I've been reading the android doc and looking for this on google but I haven't found nothing, so I don't know if even a functionality like this exists.
I'll post my code for if someone could have and idea on how to get it, but it just is the standard code for this functionallity.
First a listener for the Imageviews that when long click it starts the drag operation:
private final class MyLongTouchListener implements OnLongClickListener {
#Override
public boolean onLongClick(View v) {
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(data, shadowBuilder, v, 0);
v.setVisibility(View.INVISIBLE);
return true;
}
}
And then the Listener for the drop operation in the destiny imageview:
class MyDragListener implements OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
//...
break;
case DragEvent.ACTION_DRAG_ENTERED:
//...
break;
case DragEvent.ACTION_DRAG_EXITED:
//...
break;
case DragEvent.ACTION_DROP:
//...
break;
case DragEvent.ACTION_DRAG_ENDED:
//...
break;
default:
break;
}
return true;
}
}
A still don't know if that functionality exists, but I've found a way to get a similar result.
When you want to do the reset, just do finish() and then launch an intent to restart the activity.
This would leave the things as at the begining, but maybe in some cases won't be useful. For me works.
Related
I want to highlight text and then drag and drop it to a specific area. I know how basic drag and drop works and how to get the selected area to a String.
But I don't know how to to attach a setOnClickListener on a String? Anyone have any idea or is that a total wrong approach?
The string is in an editView
et =(EditText)findViewById(R.id.et);
int startSelection=et.getSelectionStart();
int endSelection=et.getSelectionEnd();
test = et.getText().toString().substring(startSelection, endSelection);
As the commenters pointed out, you can not set a a touch listener on a String, you have to do it on your EditText. You would do something like this:
et.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
et.setFocusable(true);
et.requestFocus();
// Do what you want
break;
case MotionEvent.ACTION_UP:
// Do what you want
break;
default:
break;
}
return true;
}
});
But still, I do not understand why do you want to use a OnTouchListener and not a OnDragListener, which seems to serve your purpose better...
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 have
RelativeLayout
A---BIG IMAGE
B---MEDIUM IMAGE
C---SMALL IMAGE
The picture is looking like this
I have used below java code
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
// LEFT
case R.id.tblLOne:
System.out.println("IMG_L_A");
playBeep(TABLA_L_BIG);
changeLeftDrum();
break;
case R.id.tblLTwo:
System.out.println("IMG_L_B");
playBeep(TABLA_L_MID);
changeLeftDrum();
break;
case R.id.tblLThree:
System.out.println("IMG_L_C");
playBeep(TABLA_L_SMALL);
changeLeftDrum();
break;
return false;
}
return true;
}
Problem is that whenever I click on small (BLACK) Image
I got following output
IMG_L_A
IMG_L_B
IMG_L_C
Whenever I click on Middle Image I got
IMG_L_A
IMG_L_B
On OuterImage big image
IMG_L_A
Why I am getting it's all behind ImageView's OnTouch Method
It is working perfect with onClick but not with OnTouch
It's because the views are stacked on top of each other.
The important point here is to know the importance of the Boolean flag that you return from your onTouchListener. The boolean flag tells android if the event was consumed or not.
Suppose, you touch tblRthree, the case R.id.tblLThree executes, but then since you return false, it appears to android that the event was not consumed and this event bubbles up to the tblRTwo view which is just behind tblRthree view, which executes the same listener for the case R.id.tblLTwo but then again you return false so, it bubbles up to view tblROne and all three cases execute.
You should return true whenever you consume the event, and false when you don't.
onTouch method will be called in multiple events, all you need is to check whether it is MotionEvent.ACTION_DOWN or not.
So, it will look something like this:
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()!=MotionEvent.ACTION_DOWN)
{
return false;//we are not going to handle it
}
switch (v.getId()) {
// LEFT
case R.id.tblLOne:
System.out.println("IMG_L_A");
playBeep(TABLA_L_BIG);
changeLeftDrum();
break;
case R.id.tblLTwo:
System.out.println("IMG_L_B");
playBeep(TABLA_L_MID);
changeLeftDrum();
break;
case R.id.tblLThree:
System.out.println("IMG_L_C");
playBeep(TABLA_L_SMALL);
changeLeftDrum();
break;
}
return true;//we have handled it
}
Im using view.startDrag() to start dragging operation. While dragging, events are received in OnDragListener. Also im using DragShadowBuilder to show the last image of View B while dragging.
Is there a way to stop or cancel or abort dragging from some external events or operation? for example, there are 2 view, View A and View B, i'm dragging View B over View A. While dragging, due to some external event or operation, i want to cancel dragging operations or cancel OnDragListener (without removing my finger from the view B).
Code Snippet for DragShadowBuilder:
DragShadowBuilder shadowBuilder = new DragShadowBuilder(view) {
#Override
public void onDrawShadow(Canvas canvas) {
canvas.drawBitmap(b, 0, 0, new Paint());
super.onDrawShadow(canvas);
}
};
boolean dragSuccess = false;
dragSuccess = view.startDrag(null, shadowBuilder, view, 0);
Code Snippet for OnDragListener:
private final class ViewDragListener implements OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
log("ACTION_DRAG_STARTED");
break;
case DragEvent.ACTION_DRAG_ENTERED:
log("ACTION_DRAG_ENTERED");
break;
case DragEvent.ACTION_DRAG_EXITED:
log("ACTION_DRAG_EXITED");
case DragEvent.ACTION_DROP:
log("ACTION_DROP");
mX = (int) event.getX();
mY = (int)event.getY();
break;
case DragEvent.ACTION_DRAG_ENDED:
log("ACTION_DRAG_ENDED");
//Doing some cleanup operations.
break;
case DragEvent.ACTION_DRAG_LOCATION:
log("ACTION_DRAG_LOCATION");
break;
default:
break;
}
return true;
}
}
I couldn't find any trick for this. I tried sending a motion event of ACTION_UP and it did nothing. As long as the user's finger is held down, there's no interrupting the event hierarchy, it seems. I found nothing to help with a google search.
I just set a global and waited until the drag ended, then proceeded.
I'm trying to use Android's new Drag&Drop framework and I run into the following issue:
how can I pass Objects name in a DragEvent, so that it can be instantiated on ACTION_DROP?
How can I pass a link to an existing Object(a View) so that it can be moved to a new place on ACTION_DROP?
I'm operating inside of one single Activity, so Class Sources are available.
You could try a number of things. In my app, this is how i did it:
public boolean onLongClick(View v)
{
dragged_view = v;
removeTransition(v);
ClipData data = ClipData.newPlainText("path", ((TextView)v.findViewById(R.id.file_name)).getText());
v.startDrag(data, new Shadow(v, c), v, 0);
return true;
}
I trigger the drag even on a long click gesture. I have a global View variable named dragged_view so that I can reference it on ACTION_DROP.
Another thing I did is pass the View as the local state object in the startDrag() method (it's the 3rd argument). I can then get it via getLocalState() and use it for reference, as in this code snippet:
item_drag_listener = new View.OnDragListener(){
public boolean onDrag(View v, DragEvent event){
if (event.getLocalState() == v)
return true;
overlays = v.findViewById(R.id.copy_move_overlays);
switch (event.getAction()){
case DragEvent.ACTION_DRAG_ENTERED:
overlays.setVisibility(View.VISIBLE);
break;
case DragEvent.ACTION_DRAG_EXITED:
overlays.setVisibility(View.INVISIBLE);
break;
case DragEvent.ACTION_DRAG_STARTED:
return true;
case DragEvent.ACTION_DROP:
return true;
}
return false;
}
};
I implemented dragging and dropping a view, by introducing a DragHandler class with a variable
View isDraggedNow;
This Variable allwasy contains a dragged view, so every class can easily take it on DragEvent.ACTION_DRAG_ENTERED