Android 3 : Drag-and-Drop Views - android

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

Related

How to define up and down arrow in custom android keyboard

I have created android keyboard and I am creating arrows to move the cursor in the user input, I could do the left and right but I couldn't know how to write the code for the up and down .. here is the code
switch (arrow){
case KEY_LEFT:
CharSequence leftText = getCurrentInputConnection().getTextBeforeCursor(1000, 0);
int leftLen = leftText.length() ;
getCurrentInputConnection().setSelection(leftLen-1, leftLen-1);
break;
case KEY_RIGHT:
CharSequence rightText = getCurrentInputConnection().getTextBeforeCursor(1000, 0);
int rightLen = rightText.length() ;
getCurrentInputConnection().setSelection(rightLen+1, rightLen+1);
break;
case KEY_UP: case KEY_DOWN:
break;
}
can any one help me implementing the down and up ??
If you just want to move cursors
https://developer.android.com/reference/android/inputmethodservice/InputMethodService.html#sendDownUpKeyEvents(int)
Try use sendDownUpKeyEvents method
sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT);
Will simply do the work.
First of all, I recommend doing something like this to check for key presses
myEditText.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v,
int keyCode,
KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
moveCursorLeft();
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
moveCursorRight();
return true;
case KeyEvent.KEYCODE_DPAD_UP:
moveCursorUp();
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
moveCursorDown();
return true;
}
}
return false;
}
});
I'm going off the assumption that you're programming a text editor of some sort.
The implementation for up and down depends on what you want those buttons to do, and how you've implemented things so far. For example, you could have each line as its own EditText that is kept track of in an ArrayList. Then, each time you add a new line, you can add a new EditText to the ArrayList. And when a user presses up or down, you can just change the index of the ArrayList by 1 in the correct direction.
I imagine that would be a pretty inefficient way of doing it, but it would be easy to define what up and down do. It's difficult to say more about what you should do without seeing more of your code.

How to draw a 5*5 array and move images on it

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;
}
}
});

onTouchListener in Android will detect touch on all parent view

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
}

Undo drag&drop operation

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.

android dispatchTouchEvent get tapped view

I call this function in my activity :
#Override
public boolean dispatchTouchEvent(MotionEvent touchEvent)
That allows me to process action before any components get focused or even deny the focus to these elements.
PROBLEM : I was wondering how I could know what component (View) has been touched in this function, then I could choose if I want to consumme the event or not.
UGLY SOLUTION : I'm currently having an ugly solution which is : I know the position of the component that is allowed to get the event, and I do a plenty of condition to approximately decide if the user clicked on this component.
Thanks.
You probably want to use the OnTouchListener
private OnTouchListener mOnTouchListener= new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch(v.getId()){
case R.id.id1):
// Do stuff
break;
case R.id.id2:
// Do stuff
break;
}
return false/true;
}
};
view.getid==R.id.//id in layout// condition can be checked for the required view is clicked

Categories

Resources