2

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;
}
SingleWave Games
  • 2,618
  • 9
  • 36
  • 52
  • remove MotionEvent.ACTION_MASK from switch case – AkashG Jul 25 '12 at 09:32
  • @AkashG, tried that but did not work amy other ideas? – SingleWave Games Jul 25 '12 at 09:38
  • You mean that when the user does 1st time ACTION_DOWN+MOVE+UP its ok, but next time it doesnt work? Does the second time enter on MOVE and dragging is equal true? – Dayerman Jul 25 '12 at 09:59
  • @Dayerman, that is exactly what I mean, it does not seem to get triggered a second time – SingleWave Games Jul 25 '12 at 10:02
  • Does the second time enter on MOVE and dragging is equal true? (try to debug or log) – Dayerman Jul 25 '12 at 10:03
  • It seems that it does not enter ACTION_MOVE a second time and dragging equals false. – SingleWave Games Jul 25 '12 at 10:31
  • You should put a `break;` statement on the `ACTION_DOWN` branch of the `switch` instruction, because if you don't enter in that `if` condition there, you'll also get in the `ACTION_UP` branch and I really doubt you want that(as you probably will cancel the dragging by the looks of your code). Also check the `ACTION_MOVE` branch. – user Nov 22 '12 at 12:55
  • added a break within my ACTION_DOWN after my if statement, however this is still not working and only seem to detect the first touch. – SingleWave Games Nov 23 '12 at 11:30
  • Please see my amended onTouch code (this is still not working correctly). – SingleWave Games Nov 24 '12 at 13:49
  • Try to output `event.getAction() & MotionEvent.ACTION_MASK` each time `onTouchEvent` is called (just write it to `Log`) and please post here the output after the second touch – Yury Pogrebnyak Nov 24 '12 at 20:54
  • @YuriyPogrebnyak Please see the logs that you requested on my first and second touch, on the first touch i moved the user down 2 spots, (D/Get Action:(511): 0, D/Action Mask:(511): 255),(D/Get Action:(511): 2, D/Action Mask:(511): 255). Thanks – SingleWave Games Nov 26 '12 at 11:44
  • Do you change visibility of this View to GONE at some point? If you are, you might need to reattach the listener... – Shark Nov 26 '12 at 13:19
  • @Shark having double checked my code I can confirm that I do not change my visibilty to GONE anywhere, any other ideas? – SingleWave Games Nov 26 '12 at 14:05
  • Are you sure the view doesn't go out of focus ergo not firing the touchlistener? – Shark Nov 26 '12 at 18:26

8 Answers8

1

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 
 }
Hani Hussein
  • 159
  • 4
  • Please see my amended onTouch code, although I have changed the end return back to false (this is still not working correctly though). – SingleWave Games Nov 24 '12 at 14:09
0

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

Community
  • 1
  • 1
Dayerman
  • 3,973
  • 6
  • 38
  • 54
0

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?

Community
  • 1
  • 1
NagarjunaReddy
  • 8,621
  • 10
  • 63
  • 98
0

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;
}
Mohammed Azharuddin Shaikh
  • 41,633
  • 14
  • 96
  • 115
  • Yes it does seem to be called everytime I move or touch the screen, e.g. If I move my user down 3 spaces it gets called 3 times, how can I fix my above code so that it works as should? THanks – SingleWave Games Nov 23 '12 at 11:11
  • Please see my amended onTouch code (this is still not working correctly). – SingleWave Games Nov 24 '12 at 13:50
0

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

yoah
  • 7,180
  • 2
  • 30
  • 30
  • Please see my amended onTouch code (this is still not working correctly). – SingleWave Games Nov 24 '12 at 14:08
  • Try to always return true from ACTION_DOWN. If you return false, you will never get calls for move or up. You will need to debug this: add log messages in your code and see where you get to and where you do not get to. – yoah Nov 25 '12 at 14:44
0

do not return true, but false.

if(Math.floor(touchX/totalCellWidth) == currentX && Math.floor(touchY/totalCellHeight) == currentY) 
{
    dragging = true;
    return false;
}
aldo.roman.nurena
  • 1,323
  • 12
  • 26
0

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

Sanket Kachhela
  • 10,861
  • 8
  • 50
  • 75
  • I am now returning true at the end of my switch statement, however am still getting the same issue. Please see my amended onTouch code within my question. Thanks – SingleWave Games Nov 26 '12 at 12:02
0

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

Shark
  • 6,513
  • 3
  • 28
  • 50
  • Hi, I have amended my code in the same way as mentioend above, however it is still not working. I have added my new onTouch code and error log here http://pastebin.com/mbn8mZ8g. I have also added my currentX & Y within the Logs. Finally, something to note is that my onTouch involves drawing a maze, basically the maze is 100x100 but only ever displays 5x5 therefore when the user moves, the current X&Y are changed, due to their position in the maze (this could be affected the onTouch). If we can get it sorted within next 4 hours then I can rightfully award you the bounty. Thanks – SingleWave Games Nov 27 '12 at 11:17