1

Imagine a view with, say, 4 subviews, next to each other but non overlapping. Let's call them view#1 ... view#4

All 5 such views are my own UIView subclasses (yes, I've read: Event Handling as well as iOS Event Guide and this SO question and this one, not answered yet)

When the user touches one of them, UIKit "hiTests" it and delivers subsequent events to that view: view#1

Even when the finger goes outside view#1, over say view#3.

Even if this "drag" is now over view#3, view#1 still receives touchesMoved, but view#3 receives nothing.

I want view#3 to start replying to the touches. Maybe with a "touchedEntered" of my own, together with possibly a "touchesExited" on view#1.

How would I go about this?

I can see two approaches.

  1. side step the problem and do all the touch handling in the parent view whenever I detect a touchesMoved outside of view#1 bounds or,
  2. transfer to the parent view telling it to "redispatch". Not very clear how such redispatching would work, though.

For solution #2 where I am getting confused is not about the forwarding per se, but how to find the UIVIew I want to forward to. I can obviously loop through the parent subviews until I find one whose bounds/frame contain the touch, but I am wondering if I am missing something, that Apple would have already provided but I cannot relate to this problem.

Any idea?

Community
  • 1
  • 1
verec
  • 5,224
  • 5
  • 33
  • 40

2 Answers2

1

I have done this, but I used CALayers instead of sub-UIViews. That way, there is no worries about the subviews catching/redispatching events to the parent UIView. You might not be able to do that, but it does simplify things. My solution tended to use CGRectContainsPoint() a lot.

colbadhombre
  • 803
  • 8
  • 11
1

You may want to read Event Handling again, as it comes pretty close to answering your question:

A touch object...is associated with its hit-test view for its lifetime, even if the touch represented by the object subsequently moves outside the view.

Given that, if you want to accomplish your goal of having different views react to the user's finger crossing over them, and if you want to do it within the touch-handling mechanism provided by UIView, you should go with your first approach: have the parent view handle the touch. The parent can use -hitTest:withEvent: or -pointInside:withEvent: as it's tracking a touch to determine if the touch is in one of the subviews, and if so can send an appropriate message.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • I was thinking along the lines of issusing an UIApplication.beginIgnoringInteractionEvents when touch-drag-outside, in the hope of getting a touchCancelled event as a result. I would then call UIApplication.endIgnoringInteractionEvents, in the hope that I would get a touchedBegan on the new view by virtue of the finger being over it. I'll give this a try when I return to that part of the code :) – verec Apr 02 '12 at 01:48
  • It's generally better to work with the framework than to work against it. Trying to trick it into canceling a touch is probably going to be more troublesome than helpful. – Caleb Apr 02 '12 at 02:02
  • In general I would tend to agree, but I am not that keen on replicating by myself what iOS does already correctly for me. The "parent handles children touches" solution means that I will end up with only one set of touchesBegan ... touchesCancelled in parent, that will have to synthesise my own variant of myTouchBegan...myTouchCancelled: MyUITouch etc ... in each of the children. The alternative is to not use views at all but shapes/path/images of some sort and handle the whole thing in one monolithic way. This stinks a bit ... – verec Apr 02 '12 at 02:10
  • But a touch *does* have just one beginning and one ending. You're trying to recast `-touchesBegan` to mean that a touch has entered a view. You could add `-touchesEntered` and `-touchesExited` methods to UIResponder, and then create a UIView subclass that sends those messages to any subviews. That'd give you a clean, reusable solution upon which to base your parent view. – Caleb Apr 02 '12 at 02:25
  • Interesting idea! Pondering it :) Many Thanks – verec Apr 02 '12 at 02:43