Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forward Touches and Gestures to Views from UIScrollview

I have some trouble with forwarding gestures and touches. I played around with it quite a bit, but i cant get it working the way I want.

Basically I want to control a scrollview on a dualscreen with 2 fingers and forward everything else to the ipad-views behind a overlaying scrollview.

To be able to control the scrollview on the dualscreen I subclassed UIScrollView and added it as a overlaying view with a clear background to the ipad-screen.

Then I hooked it up with a delegate to forward its dragging and stuff to the scrollview on the dualscreen. this works perfectly.

As I wrote I want the scrollview to respond just to 2 finger-scroll, so i set it to

ScrollView.panGestureRecognizer.minimumNumberOfTouches = 2;

But the scrollview eats up all touches and I dont get it right to forward everything else but 2 finger touches to the views behind. I think overriding the

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

must do the trick, but I don't get it right to detect the number of fingers on the screen right.

like image 803
Tom Avatar asked Nov 01 '13 08:11

Tom


2 Answers

I'd like to share/explain the solution to the problem. That said I also want to point out that hatfinch input led me in the right direction. thank you very very much mate!

The problem when attempting to put a view/scrollview as an overlaying toplayer is that the toplayer doesnt know about its "next responder". putting the view/scrollview as a underlaying view will solve this problem. you may need to fine tune the touch behaviour of any scrollview within that underlaying scrollview to get the behaviour right (like setting maximum number of touches)

The solution is to subclass a UIScrollview, override this methods override the touchesBegan: and other touch methods as follows (see user1085093 answer), and add it as underlaying view to the ipad-screen.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

// If not dragging, send event to next responder
if (!self.dragging){
    [self.nextResponder touchesBegan: touches withEvent:event];
}
else{
    [super touchesBegan: touches withEvent: event];
}}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

// If not dragging, send event to next responder
if (!self.dragging){
    [self.nextResponder touchesMoved: touches withEvent:event];
}
else{
    [super touchesMoved: touches withEvent: event];
}}


-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

// If not dragging, send event to next responder
if (!self.dragging){
    [self.nextResponder touchesEnded: touches withEvent:event];
}
else{
    [super touchesEnded: touches withEvent: event];
}}

i did the setup of the scrollview like this:

 TopLayerScrollView *newScrollView = [[TopLayerScrollView alloc] init];
[newScrollView setBackgroundColor:[UIColor clearColor]];
[newScrollView setFrame:self.tabBarController.view.frame];
[newScrollView setContentSize:dualScreenViewController.scrollContent.contentSize];
newScrollView.showsHorizontalScrollIndicator = NO;
newScrollView.showsVerticalScrollIndicator = NO;
newScrollView.delegate = self;
newScrollView.bounces = NO;
[newScrollView scrollsToTop];
newScrollView.panGestureRecognizer.minimumNumberOfTouches = 2;

self.topLayerScrollView = newScrollView;
[newScrollView release];

[self.tabBarController.view removeFromSuperview];
[topLayerScrollView addSubview:self.tabBarController.view];
[window addSubview:topLayerScrollView];
[topLayerScrollView bringSubviewToFront:self.tabBarController.view];

The delegate method of the underlaying scrollview:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView.dragging || scrollView.tracking)
{
    [dualScreenViewControlleremphasized text.scrollContent setContentOffset:CGPointMake(scrollView.contentOffset.x, scrollView.contentOffset.y) animated:NO];
    self.tabBarController.view.frame = CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y, self.tabBarController.view.frame.size.width, self.tabBarController.view.frame.size.height);
}}

This solution works great. The other solution would be to have a scrollview as an overlaying view as I first intended. As said the problem is to let the toplayer view know about the views(nextResponder) benath it. To achive this you must sublass UIScrollview and create a UIResponder-property you must hookup either in your interface-builder file or during runtime. this way the overlaying scrollview will know who is the next responder. please see morningstar's answer

like image 76
Tom Avatar answered Nov 08 '22 07:11

Tom


Unfortunately, you can't do anything with -pointInside:withEvent: here because the system decides which view the touch is in (or which views the touches are in) before it determines whether they satisfy the requirements of the gesture recogniser.

I think your best bet here is to have the view that is currently behind the scrollview actually be the content view of the scrollview, and to move that view every time the content offset of the scroll view changes to keep it in the same position on the screen. (This sounds expensive but it's not really.) So instead of being an overlay, your scroll view is more like an underlay.

You may also wish to play with UIScrollView.delaysContentTouches, -[UIScrollView touchesShouldBegin:withEvent:inContentView:], etc. to refine the behaviour.

like image 31
hatfinch Avatar answered Nov 08 '22 07:11

hatfinch