0

I want to get the current object touched in touchesMoved. This is not to be confused with the touchLocation (CGPoint), but the actual object the user is touching. Using UITouch always returns the initial touch (as it says in the apple docs) rather than the current or latest touch.

I have a grid of spots (UIImageViews) that can be 3 by 3 up to 20 by 20.

As the user drags their finger on the screen a line is drawn that tracks the users finger. When a user intersects a gridspot the start point of the line snaps to that spot and continues to track the finger, Essentially allows you to draw shapes on a grid.

Currently i have a for loop that checks if the touchlocation intersects with a grid spot. This does work but is very slow for obvious reasons when their is 400 gridspots.

I have also tried Gesture recognizers but these cancel the touches.

Any help/advice will be much appreciated, thanks!

EDIT: this is what i have in my touchesMoved.

UITouch* touch = [touches anyObject];
CGPoint touchLocation =[touch locationInView:self];

for (int i=100; i<tagInt; i++) {

    UIImageView *img=(UIImageView*)[self.view viewWithTag:i];

    if (CGRectContainsPoint(img.frame, touchLocation)) {
       //Drawing code  setNeedsDisplay etc
    }
 }
EagerMike
  • 2,032
  • 1
  • 24
  • 40
  • You are drawing on a grid of squares? You could do that with math only. No view-matching needed.. Basically, you should just get the location `[aTouch locationInView: containerView]` and than check the location for correctness.. – calimarkus Oct 29 '12 at 11:06
  • basically i want to check if the touchlocation intersects with 1 of the `UIImageViews` – EagerMike Oct 29 '12 at 11:11
  • How about subclassing UIImageView and then use each views own touchesMoved delegate method to find out where the touch is? – jimpic Oct 29 '12 at 11:34
  • wouldn't that just be the same, the touch wouldn't update for the current or latest touch – EagerMike Oct 29 '12 at 11:50
  • get the touch from the container view (the one, where the imageViews are added) and then get the position in that view. then check `CGRectContainsPoint(imageView.frame, touchPositionInContainerView)` for all of your up to 400 views. Is that what you're doing at the moment? show us some code please. If you're imageViews are ordered in an array e.g. left-to-right and top-down, than you could calculate the position. viewWidth / imageWidth = horizontal position, same for the vertical position with the heights. (and take margins in account, if you have margins) – calimarkus Oct 29 '12 at 12:20
  • "Using UITouch always returns the initial touch (as it says in the apple docs) rather than the current or latest touch." That's not true. If you track a UITouch object, the position will always update when the finger is moved. It will exist until the touch ends and represent the latest information for that touch. However, a touch can only exist inside its initial view. Try deactivating user input for all your grid views so all touch events are fired from your main (background) view. – jimpic Oct 29 '12 at 12:39
  • @jaydee3 updated to show code, I don't use an array but tags and also sometimes the grid may be circular. – EagerMike Oct 29 '12 at 12:55
  • Use UIGestureRecognizer! UITouch is so old school! – MCKapur Oct 29 '12 at 12:56
  • Do the gesture regonizers constantly update like touchesMoved so the line can redraw to your finger every time you move oon the screen? – EagerMike Oct 29 '12 at 12:59

2 Answers2

0

As discussed in the comments to the initial question, finding the touch location from the container view seems best. The biggest bottleneck in this code is storing all your objects in one linear array, then checking each element in your array. A better method would be to store the objects in a better format where you can access individual objects based on their position.

If your objects are arranged on a strict grid, then storing them in a two dimensional array should be fast enough. Subdivide your screen into the grid divisions, then find the touchesMoved point within those grid divisions. Use those two integers as indexes to your 2D array, and check the one object available at that location in your array. If you don't have an object at every position on the grid, just store a nil at that location to tell your code "No need to check here". If you may have more than one object at each grid location you can keep a list of the objects at that location in the array, and check all objects in the list. This will be much less than the total (if your objects don't clump up).

Even if your objects are not arranged on a strict grid you can use this technique. Merely dividing your screen into 4 quadrants will reduce the time required to check your objects roughly to one fourth the initial time.

If your objects are moving you'll have to keep this array updated.

This 2D array is just my first thought on a better way of doing this, based on the limited information in your question. It may not be the best way to work in your actual program, and a different data structure and algorithms may be better suited.

Mr. Berna
  • 10,525
  • 1
  • 39
  • 42
0

You should NOT put drawing code IN the touch handling method. Perhaps the best way is to just save all touch points within a temporary mutable array. And in the drawRect method you draw the correct line once per frame. Take the logic out of the touch handling method. (Also you could make the position fixing calculations in the background, and the line will be updated, after they are finished..)

I still don't quite get what you are trying to draw. could you give us an example image?

calimarkus
  • 9,955
  • 2
  • 28
  • 48
  • Sorry the drawing code is where i have `setNeedsDisplay` not the actual drawing. Essentially what i want is to draw a line with the finger from spot to spot creating shapes. this could be a square, star, hexagon. I need a way of knowing what grid spot the finger is under so i can then draw to that spot. – EagerMike Oct 29 '12 at 16:37