SingleWave Games
SingleWave Games

Reputation: 2648

Android - onTouchEvent only working first time

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

Answers (8)

Shark
Shark

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

Sanket Kachhela
Sanket Kachhela

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

aldo.roman.nurena
aldo.roman.nurena

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

yoah
yoah

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

Hani Hussein
Hani Hussein

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

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

NagarjunaReddy
NagarjunaReddy

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

Dayerman
Dayerman

Reputation: 4003

Seems like a problem with the Mask and the event you are applying on the switch. Have a look to this issue

Upvotes: 0

Related Questions