Reputation: 2648
I have a canvas drawing which is using OnTouch, however for some reason I cannot get this to work properly. It works for the first time (the first touch movement). However when the user removes his finger the OnTouch never runs again, stopping the user from moving the character item.
Having done lots of research and various different options, I simply cannot get this to work and in doing so have noticed that ACTION_DOWN is called for the first time then on ACTION_UP is called.
Below you can find my 2 chunks of code, the first is the actual onTouchEvent. The second the chunck of code used to handle the user permission within my drawn canvas (which is maze(5 x 5) based).
Another nore to consider is the canvas is redrawn (invalidate), everytime the user position is moved (this is done square by square)
@Override
public boolean onTouchEvent(MotionEvent event)
{
float touchX = event.getX();
float touchY = event.getY();
int currentX = maze.getCurrentX();
int currentY = maze.getCurrentY();
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
if(Math.floor(touchX/totalCellWidth) == currentX && Math.floor(touchY/totalCellHeight) == currentY)
{
dragging = true;
return true;
}
break;
case MotionEvent.ACTION_UP:
dragging = false;
break;
case MotionEvent.ACTION_MOVE:
if(dragging)
{
int cellX = (int)Math.floor(touchX/totalCellWidth);
int cellY = (int)Math.floor(touchY/totalCellHeight);
if((cellX != currentX && cellY == currentY) || (cellY != currentY && cellX == currentX))
{
boolean moved = false;
switch(cellX-currentX)
{
case 1:
moved = maze.move(Maze.RIGHT);
break;
case -1:
moved = maze.move(Maze.LEFT);
}
switch(cellY-currentY)
{
case 1:
moved = maze.move(Maze.DOWN);
break;
case -1:
moved = maze.move(Maze.UP);
}
if(moved)
{
invalidate();
if(maze.isGameComplete())
{
showFinishDialog();
}
}
}
break;
}
}
return true;
}
The maze position handler code:
public boolean move(int direction)
{
boolean moved = false;
if(direction == UP)
{
if(currentY != 0 && !horizontalLines[currentY-1][currentX])
{
currentY--;
moved = true;
}
}
if(direction == DOWN)
{
if(currentY != verticalLines[0].length-1 && !horizontalLines[currentY][currentX])
{
currentY++;
moved = true;
}
}
if(direction == RIGHT)
{
if(currentX != horizontalLines[0].length-1 && !verticalLines[currentY][currentX])
{
currentX++;
moved = true;
}
}
if(direction == LEFT)
{
if(currentX != 0 && !verticalLines[currentY][currentX-1])
{
currentX--;
moved = true;
}
}
if(moved)
{
if(currentX == finalX && currentY == finalY)
{
gameComplete = true;
}
}
return moved;
}
Upvotes: 2
Views: 3903
Reputation: 6610
I thought the offending part is this one
event.getAction() & MotionEvent.ACTION_MASK
But looking at it again, it seems ok... Try replacing this with
event.getMaskedAction()
and keep that in the switch.
Or maybe you need to use ACTION_POINTER_UP instead of ACTION_UP.
Can you change this bit of code please?
case MotionEvent.ACTION_MOVE:
Log.d(LOGTAG, "ACTION_MOVE block, dragging = "+dragging);
if(dragging)
{
Log.d(LOGTAG, "Dragging fired with event: "+event.toString());
int cellX = (int)Math.floor(touchX/totalCellWidth);
int cellY = (int)Math.floor(touchY/totalCellHeight);
// ...
and post the output please.
EDIT: also, remember that you want to return true from a onlistener ONLY when you want to fully consume the event; return false if you want to propagate it further. So i guess only one of those returns need to be true and let others pass down and be handled by their respective views' ontouch handlers...
Upvotes: 0
Reputation: 10856
put return=true; instead of false in last statement of your switch case. because if you use false than it will call only one time and then no other view can get touch event of that particular view.. so use true instead of false..
THEORY
Returning true in an onTouchEvent() tells Android system that you already handled the touch event and no further handling is required. If you return false, Android system will be the handler of the onTouch event and will override your code for any events past ACTION_DOWN (which is the first event when you touch the screen).
i also had same problem and now solved. i think it may help you..
Upvotes: 0
Reputation: 1332
do not return true, but false.
if(Math.floor(touchX/totalCellWidth) == currentX && Math.floor(touchY/totalCellHeight) == currentY)
{
dragging = true;
return false;
}
Upvotes: 0
Reputation: 7230
The main issue is that you are missing a break statement at the end of each case. You fall through other cases and return false on the second ACTION_DOWN. This means that ACTION_UP and MOVE will not get called.
To fix this: - Add a break statement at the end of each case - Always return true from ACTION_DOWN
Upvotes: 0
Reputation: 169
Trying to Change final Return to True not False Like that :
@Override
public boolean onTouchEvent(MotionEvent event)
{
float touchX = event.getX();
float touchY = event.getY();
int currentX = maze.getCurrentX();
int currentY = maze.getCurrentY();
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
{
if(Math.floor(touchX/totalCellWidth) == currentX &&Math.floor(touchY/totalCellHeight) == currentY)
{
dragging = true;
return true;
}
}
case MotionEvent.ACTION_UP:
dragging = false;
return true;
case MotionEvent.ACTION_MOVE:
if(dragging)
{
int cellX = (int)Math.floor(touchX/totalCellWidth);
int cellY = (int)Math.floor(touchY/totalCellHeight);
if((cellX != currentX && cellY == currentY) || (cellY != currentY && cellX == currentX))
{
//either X or Y changed
boolean moved = false;
//check horizontal ball movement
switch(cellX-currentX)
{
case 1:
moved = maze.move(Maze.RIGHT);
break;
case -1:
moved = maze.move(Maze.LEFT);
}
//check vertical ball movement
switch(cellY-currentY)
{
case 1:
moved = maze.move(Maze.DOWN);
break;
case -1:
moved = maze.move(Maze.UP);
}
if(moved)
{
invalidate();
if(maze.isGameComplete())
{
showFinishDialog();
}
}
}
return true;
}
}
return True; // Here
}
Upvotes: 1
Reputation: 42016
I am very much sure that your Touch
is called everytime, what I doubt may be cause of your cases doesn't meet the requirement.
To cross check just put a log print
@Override
public boolean onTouchEvent(MotionEvent event)
{
System.out.println("Touch working");
return false;
}
Upvotes: 0
Reputation: 8645
here is good example of on touch may be it is usefull not sure?
public boolean onTouch(View v, MotionEvent event) {
layoutParams = (RelativeLayout.LayoutParams) ima1.getLayoutParams();
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
System.out.println("value of x" +x_cord);
System.out.println("value of y" +y_cord);
if (x_cord > windowwidth) {
x_cord = windowwidth;
}
if (y_cord > windowheight) {
y_cord = windowheight;
}
layoutParams.leftMargin = x_cord-25;
layoutParams.topMargin = y_cord-25;
// layoutParams.rightMargin = x_cord-25;
// layoutParams.bottomMargin = y_cord-25;
ima1.setLayoutParams(layoutParams);
break;
default: break;
}
return true;
}
});
ima2 = (ImageView)findViewById(R.id.imageview2);
ima2.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
layoutParams = (RelativeLayout.LayoutParams) ima2.getLayoutParams();
switch(event.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
System.out.println("value of x1" +x_cord);
System.out.println("value of y1" +y_cord);
if (x_cord > windowwidth) {
x_cord = windowwidth;
}
if (y_cord > windowheight) {
y_cord = windowheight;
}
layoutParams.leftMargin = x_cord - 25;
layoutParams.topMargin = y_cord - 75;
ima2.setLayoutParams(layoutParams);
break;
default: break;
}
return true;
}
});
}
}
this is example Android Drag and drop images on the Screen?
Upvotes: 0