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.
Related
(I deleted all code, because the below code is not working either.)
Additional information and short summary - the real problem
This is interesting. I have another project a simple activity. There, I can drag. Now in this project, I block commented everywhere. There are only a few lines, like another project, but still no drag.
Drag is in progress, but there is no drag window handle.
Sometimes it says. I also searched it, but I could not do it.
The code is now:
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "matching ggame OnCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_matchgame);
setupForGame();
Log.d(TAG, "matching game OnCreate ends");
}//oncreate end
void setupForGame(){
Log.d(TAG, "matching game setupforgame");
imageAnswer = (ImageView) findViewById(R.id.imgAnswer);
imageAnswer = (ImageView) findViewById(R.id.imgAnswer);
}
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d(TAG, "ontouch never");
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;
}
}
#Override
public boolean onDrag(View receivingLayoutView, DragEvent dragEvent) {
Log.d(TAG, "ondrag start");
And still not going inside.
I made it static to see if that is the problem.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:id="#+id/relative_layout"
tools:context=".games.MatchingGame">
<ImageView
android:id="#+id/imgAnswer"
android:layout_width="111dp"
android:layout_height="111dp"
android:src="#drawable/b3_1"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
/>
</RelativeLayout>
It is same as another project, but it is not working. I looked at all possibilities and debugged.
And please don't ask for drag method code; it is not important. It can't enter it.
When I hold and drag image, this comes to the log in a loop until I leave:
I/SPRDHWComposer: util[1759] warning: osdLayer width 111, stride 112, not equal!
And when I leave the image:
V/WindowManager: rotationForOrientationLw(orient=0, last=1); user=0 USER_ROTATION_LOCKED sensorRot
V/WindowOrientationListener: getProposedRotation : mEnabled = false, mUsedautorotioansensor =true
W/WindowManager: Drag is in progress but there is no drag window handle.
I also made this if the touch is problem, but it is still the same:
imageAnswer.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
//if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "ontouch down");
//Log.d(TAG,"parent "+ String.valueOf(img1.getParent()));
Log.d(TAG, "view "+String.valueOf(v));
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(data, shadowBuilder, v, 0);
v.setVisibility(View.INVISIBLE);
return true;
This is my old project that works with drag and drop. I can't see the difference:
https://gist.github.com/anonymous/540a70e05de6d765e20896b47deb7eb2
When I do this
imageAnswer.setOnDragListener(new View.OnDragListener() {
public boolean onDrag(View v, DragEvent event) { Log.d(TAG, "drag");
return false;
}
});
It does not work either. No log.
Also this does not give a log:
imageAnswer.setOnDragListener(new dropListener());
private class dropListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {Log.d("Chic","ondrag");
switch (event.getAction()) {
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;
}
}
There is difference between the two projects:
Can this be the reason?
I tried also to put all setondrag setontouch inside oncreate.
As far as I seen (for example, here), onTouch and onDrag simply don't work together. Why not put all of you code in in onDrag? Judging by your code, it should be enough.
Use TouchImageView instead of ImageView.
With the reference of that site:
TouchImageView extends ImageView and supports all of ImageView’s functionality.
In addition, TouchImageView adds pinch zoom, dragging, fling, double tap zoom functionality and other animation polish. The intention is for TouchImageView to mirror as closely as possible the functionality of zoomable images in Gallery apps.
The problem will be solved it will support both Drag as well as Touch.
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'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.
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.
I've got an Activity with several ImageViews, each with its own OnDragListener and OnTouchListener. When I'm clicking over the display with two fingers at once, and I click on 2 images at the same time, the app sometimes crashes.
How could I block start of another drags and touches at display when one item is actually dragged? I've tried to put setClicable(false) to the whole layout, but it didn't work.
class MyDragListener implements OnDragListener {
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.game_layout);
#Override
public boolean onDrag(View dropView, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
mainLayout.setClickable(false);
return true;
case DragEvent.ACTION_DRAG_ENTERED:
// some code
return true;
case DragEvent.ACTION_DROP:
// some code
return false;
case DragEvent.ACTION_DRAG_ENDED:
mainLayout.setClickable(true);
// some code
return true;
default:
break;
}
return true;
}
}
EDIT: An idea came to my mind - when an item is clicked, remove OnTouchListeners from every other images. But it would be additional load for CPU on every touch. Isn't there a better way? -->> also NOT WORKING
EDIT2: ACTION_DOWN -> inAction = true; and it's still not working. When I drag an image over another one and make second, third... touch, it a) drops a picture or worse b) NullPointerException
private final class MyTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d(TAG, "" + inAction);
if(motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
if(!inAction) {
inAction = true;
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
view.setVisibility(View.INVISIBLE);
return true;
}
else
return true;
}
else if(motionEvent.getAction() == MotionEvent.ACTION_UP) {
inAction = false;
return true;
}
else {
return false;
}
}
EDIT3: I'm using style with false android:windowEnableSplitTouch for the whole application
<style name="MyTheme" parent="#android:style/Theme.NoTitleBar.Fullscreen">
<item name="android:windowEnableSplitTouch">false</item>
<item name="android:splitMotionEvents">false</item>
</style>
You can simply return; if a flag is true. Namely, set a flag when any of the listeners is triggered. Haven't you thought about it?