How to block dragging multiple items at once - android

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?

Related

After ontouch, it can't go ondrag on Android

(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.

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

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.

DragDrop application goes wrong when changing screen size

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.

Move Events AFTER LongPress

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

Categories

Resources