2

I have a question that I've searched but can't find a definative answer to. Here is my layout:

UIView - ViewController   
   |_UIScrollView - added programatically
      | |_UIView to hold a backgound/perimeter  - added programmatically
      |_UIView 1 - added programmatically
      |_UIView 2 - added programmatically
       and so on

My question is how come the ViewController calls "touchesMoved" only once when I move say UIView 2 on touch?

Now UIView has it's own touchesMoved method, but I need the controller's touchesMoved to get called as I need it to talk to the ScrollView to update its position. Such as when that UIView 2 is near the corner, so that the ScrollView moves a little to fully show UIView 2.

If there is no way around this is there a way to update ScrollView from UIView 2 to scroll when its near a corner?

Edit:

I think I may have found a work around. Not sure if this will be accepted by Apple but:

I just made a call to a instance variable that is = to self.superview which then allows me to talk back to my ScrollView within UIView's touchesMoved

in that i can call the method [ScrollView setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated] so my ScrollView gets updated as the subview(UIView2) moves close to the edge of the UIWindow.

Thank you for the suggestions.

Konrad Winkowski
  • 2,022
  • 1
  • 13
  • 15
  • if your concern is about casting `self.superview` to `UIScrollView` and sending it the `setContentOffset:` message, this is perfectly legal. – sergio Sep 14 '12 at 20:52
  • Great! thank you. I was worried that would cause issues. Thank you so much for your help sergio. – Konrad Winkowski Sep 14 '12 at 22:19

1 Answers1

3

The behavior you describe is the result of the UIScrollView hijacking the touch moved event. In other words, as soon as the UIScrollView detect that a touch moved event falls within its frame, it takes control of it. I experienced the same behavior while trying so create a special swipe handler, and it failed each time a UIScrollView was also interested by the swipe.

In my case, I solved the issue by intercepting the event in sendEvent: overridden in my custom UIWindow, but I don't know if you want to do the same. In any case, this is what worked for me:

- (void)sendEvent:(UIEvent*)event {
NSSet* allTouches = [event allTouches];
UITouch* touch = [allTouches anyObject];
UIView* touchView = [touch view];

//-- UIScrollViews will make touchView be nil after a few UITouchPhaseMoved events;
//-- by storing the initialView getting the touch, we can overcome this problem
if (!touchView && _initialView && touch.phase != UITouchPhaseBegan)
    touchView = _initialView;

    //-- do your own management of the event

    //-- let the event propagate if you want also the default event management
[super sendEvent:event];

}

An alternative approach that you might investigate is attaching a gesture recognizer to your views -- they have a pretty high priority, so maybe the UIScrollView will not mess with them and it might work better for you.

If there is no way around this is there a way to update ScrollView from UIView 2 to scroll when its near a corner?

Have you tried to make the UIScrollView scroll by calling:

- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
sergio
  • 68,819
  • 11
  • 102
  • 123
  • Where would I add the -(void)sendEvent? Also, yes I did try to call "setContentOffset" from my UIViewController but that does not get a updated position of UIView 2 so it only scrolls on the first touch. Then as I move the view around it does not scroll. So what I need to be able to do is move the UIView 2 inside the scroll view && move the scrollview if UIView 2 is near the edge of the ViewController – Konrad Winkowski Sep 14 '12 at 16:12
  • sendEvent... you should define your custom `UIWindow` class and define it there; then you should use this window type instead of the default one (e.g., set the main window class type in Interface Builder, or set it programmatically in appDidFinishLoading, depending on how you do it) – sergio Sep 14 '12 at 16:14
  • see also this post for details about overriding the window type: http://stackoverflow.com/questions/7883886/where-can-i-change-the-window-my-app-uses-from-uiwindow-to-my-own-subclass-mywi – sergio Sep 14 '12 at 16:15
  • in any case, my suggestion would be to first try and use a gesture recognizer to handle the movement of your inner view... that would be so much simpler (it may work, or may not, but it is very easy to implement). – sergio Sep 14 '12 at 16:33
  • Well I have no problem moving the subview of the ScrollView (UIView 1,2, ...) my problem is getting them to talk back to the ScrollView to tell it to scroll or having the ViewController handle that, but when I do try that UIViewControllers touchesMoved gets called only once while UIView2 touchesMoved keeps getting called. I besically need to know how to talk back to my ScrollView to update its position every time UIView 2 is moved( or ScrollView subview) – Konrad Winkowski Sep 14 '12 at 16:37