Is it possible to call 'touchesEnded' myself, from within, say, 'touchesMoved'?
I am trying to take out everything I have in 'touchesEnded' and put it in another method, and call that from both 'touchesMoved' and 'touchesEnded' if I need to, but if I could do it straight from 'touchesMoved', that would be easier as I wouldn't have to do anything to the 'touch' event - I've tried saving the point itself, but I'm not sure that it is still doing what I want, somehow.
Or, is there a better way to accomplish the following:
I want to drag my 'cards' (subviews) around the screen, but so they slide underneath other things on the screen.
What I had was the touches methods in the 'card' class. When the touch began or moved, the card was sent to the back of all the others, and then moved its frame according to the touch. The touch was restricted to that view, so it was easy to determine and follow, and only touches in that view were considered. BUT, moving the subview's position (sending it to the back) caused problems with the 'touch', which disappeared from events after the subview position changed, causing problems if the view changed during 'touchesMoved' (like wiht an incoming phone call).
So, I then moved the touchesMethods to the view controller. It's OK, and I think I've got it all working there, and it does seem to solve the problem of the incoming phone calls, etc. But instead of the touch being restricted to the single (small) subview already, I have to find ways to test if it's in the view in question. If it is, I then move that view. According to the logic I have, if the subview always moves with the touch, then the touch should always stay in the same place in relation to the frame, shouldn't it? And yet it doesn't, if you move things really fast (slightly unnatural in that it's not what the user is meant to do, but a lot of them seem to try it!). It seems totally possible for the touches to move too fast for the changing card frame to keep up. Thus you get the situation where you are no longer having touches within the area of the card subview, even when you have never lifted your finger. All I can think of is that the graphics can't keep up with the speed of the touches moving. Would that be why? I can't see how else, logically, that could occur.
So I thought I would try to make it act like the touch had ended, if it ever left the area of the subview, even if the person's finger is still moving elsewhere on the screen. I would test whether the current touch was still in the area of the card, and if not, call touchesEnded with the same touch and event. Is that a good way of doing this? It's not working so far by saving the point, because the point is now outside the area of interest, and it's hard to distinguish whether it *had* been part of a moving touch or just happened to be in that spot. And otherwise I get into complicated things where I have to have more variables to try to keep track of that. My 'touches' methods are already nests of if statements! (I'm sure there are better ways to have done that, but it was my first attempt).
Would this type of solution re-create what happened when I had the touchesMoved method in the subview rather than the view controller? Then you never seemed to get the situation where the touches got ahead of the graphics - or if you did, those touches didn't get processes, and the decision not to process them was so fast that it wasn't noticeable. Now it's definitely noticeable. Can anyone explain to me what the difference is, what exactly is happening when the touches were in the Card method, why it never got ahead of itself the way it does now - I had thought that it would send 'toucheEnded' if the touch ever left the area of the Card, but no matter how fast you drag your finger, that never seems to happen - you can always keep hold of the card. (touches Ended would send it back to its starting position, amongst other things).
The only other possible solutions I could think of were:
a) slow down the rate that touchesMoved gets new touches - is that possible? To make it keep time with the rate at which the cards can be redrawn.
or
b) speed up the drawing, if that is a problem. I don't see why it should be really, they are just .png files, 52x82 pixels, not very big, displayed in the centre of an image view. They do have a little transparency in the corners to make them rounded rectanges, but I can't see why that should slow it down so much.
thanks. That's what I'd thought. but when I tried it, it didn't seem to work - it never got called. But maybe I did something wrong.
If I did that, would it actually use the same 'touch' event, and then get rid of it in the way that -touchesEnded normally does?
One problem that I am having currently is that if I try to move something really fast (just testing the limits, not because the use really needs to do that in my app), BOTH touchesCancelled and touchesEnded can be called after touchesMoved. That then starts my other method off twice, causing some kidns of race condition errors at times. What I really want to find a way of doing is 'clearing the touches queue' when something happens - like when the touch first moves out of the target area, or when touches are cancelled, or when touches end. I want all three of those things to trigger a method that can happen only ONCE. Currently, the method might be triggered from within touchesMoved when the touch moves out of the target area. But before it gets very far into that method (not far enough to trigger commands that disable user interaction, for example), it seems that other 'touchesMoved' events have stored up, as potentially have -touchesCancelled or -touchesEnded events. So those start to be processed as well, also triggering this method.
Is there something I could put in the start of that method, that would 'clear the queue' of any other touch events that are being stored up or that are also being processed at the same time?
I had hoped that making -touchesMoved and -touchesCancelled just call -touchesEnded from within them would accomplish that, but I think that it probably still won't do it: I might still get a subsequent -touchesEnded message somehow.
I don't really understand how it's possible to get both -touchesCancelled and -touchesEnded happening virtually simultaneously (so much so that log statements that happen in the first two lines of each one, end up alternating in the log!). I don't think there is a touchesBegan that happened in between (though it's possible, as I didn't have a log statement in there). But at any rate, I'm getting too many things happen at the same time, and I don't want it!!!
touchesEnded doesn't actually get rid of the touch, it's just called when the touch ends, but if you're calling it from touchesMoved, you can pass the same touches and event to touchesEnded.
About calling the method more than once, try setting a BOOL at the beginning of the method you want to call just once, called shouldRun or something. Before you call the method, check that shouldRun is YES.
So when the method starts, set shouldRun to NO, and when it's finished, set it to YES.
thanks. That does make sense, yes. I have sort of tried to do that with a variable being set in -touchesBegan, and reset at the start of the touchesCancelled or Ended methods, so that I could keep checking whether it was part of a previous 'drag' or not, as I only want it to respond once to that, but I guess I could do another that starts at the beginning of the new method, and hope that it ends up not being called simultaneously from two different methods (cancelled and ended). I thought I had various things in there that would disable user interaction, but they don't seem to be being set fast enough to actually stop all the touches that are being queued up, hence the need for these extra steps.
It was a lot easier to keep track of where the touch was and whether it was in the view or not, when the touch methods were all in the subview class rather than the view controller. Now it just seems that I am endlessly checking where the touch is and whether it's part of a previous touch and whether there is a game happening and whether the touch is this or that or the other, and whether some other variable is set, etc etc etc. It seemed a lot simpler to handle this sort of touch in the subview class, at least until the point where I tried to change the subview's position above or below the other subviews, at which point it all went horribly wrong.
So no way to make the touchesMethod rate slow down, I guess, and not other ideas of how to speed up the graphics display to keep up with it? I still can't really see why the touchesMoved gets ahead, since I thought I was changing the subview position every time the touch moved, so that it should keep perfectly in position relative to where it started. But in practice, it doesn't work like that - not when it's done really quickly, anyway.
As far as I know there isn't any way to slow the touches down. As for speeding up the graphics, you might want to take a look at openGL. I've never used it myself, but I hear it's pretty fast graphic-wise.
And now I'm back to -touchesCancelled not being called again, on incoming calls!!!
I don't get it.
I've got all my BOOLs in there now to check that the drag is part of a sustained drag, that the right card is being touched, that it's still in the right area, that the method it triggers only gets called once, etc.
And I wanted one more, so that if a call came in when the card was being moved, the method would be triggered so that the card would go back to its starting place rather than just being left where it happened to be at the end of 'touchesMoved'. And it was working, I thought, for a while - but now -touchesCancelled just doesn't seem to be called. Only ApplicationWillResignActive.
It's not as bad as before, because at least now, the card isn't frozen when you come back to the screen - it all works fine. But I don't understand why the touchesCancelled method isn't triggered so that I can do the clean-up stuff. I still wonder if it's something to do with it processing a whole queue of other touch events still and just not having time to get to touchesCancelled before the application resigns, but I can't see why that should happen. The graphics are not very intense (just 50x80 pixel png files, being dragged around).
I could put it in ApplicationWillResignActive, but that would mean another whole lot of BOOLs to check that it's in this particular stage of the program when that happens, because I only want this method happening during the game. Plus it would still worry me that there is something else that I have done wrong that is messing around with things, and might somehow cause unexpected things to happen in some mysterious future circumstance.