mutualmobile / MMDrawerController

A lightweight, easy to use, Side Drawer Navigation Controller
MIT License
6.76k stars 1.38k forks source link

Conflict: UIScrollView in CenterViewController #229

Closed zhw511006 closed 10 years ago

zhw511006 commented 10 years ago

I have a UIScrollView in CenterViewController and the scrollview has three pages. When in first page, swipe to right, I hope to open the LeftViewController, how to deal with the conflict pan gesture, Thank you very much!

Sylvain-B commented 10 years ago

I have the same issue, it's nearly impossible to open drawer using pan gesture (MMOpenDrawerGestureModeBezelPanningCenterView) when the center view controller uses a horizontal scrollview.

I tried to use setGestureShouldRecognizeTouchBlock (with MMOpenDrawerGestureModeCustom), but the issue remains even if the block returns YES

Thanks!

cherishloveyou commented 10 years ago

have the same problem. In addition,my centerViewController is a Tableview ,so I push a SubViewController from CenterViewController. In SubViewController the gesture can open drawer also,it's error. How to disabled it, should I close MMOpenDrawerGestureModePanningCenterView before push SubViewController ,and then open MMOpenDrawerGestureModePanningCenterView after popup SubViewController ? it's feel suffer,MMDrawerController is powerful, but we need more demo to show it's usage.

kcharwood commented 10 years ago

The example app has a table view for the center view controller.

If you have a scroll view that allows for horizontal scrolling in the center view controller, I would recommend disabling the center pan gesture as not to confuse the user from a UX perspective.

Or you could use the bezel pan instead.

Sylvain-B commented 10 years ago

Bezel pan is not working either, that was the point of my comment

kcharwood commented 10 years ago

This is more of a UIGesture problem than a MMDrawerController problem.

UIGestureRecognizerDelegate provides methods for managing gesture conflicts, and UIScrollView exposes the gestures that are used so you can provide more fine grained control.

If you combine those with setGestureShouldRecognizeTouchBlock on drawerController, you should be able to manage the conflict.

farfromrefug commented 10 years ago

It s actually not as easy as it seems and can't only be achieved with the setGestureShouldRecognizeTouchBlock To achieve it i had to use shouldRequireFailureOfGestureRecognizer to actually disable the scrollview gesture (was the only way)

What i do is this

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if (gestureRecognizer != self.panGesture || self.openSide != MMDrawerSideNone) {
        return NO;
    }
    CGPoint velocity = [self.panGesture velocityInView:self.panGesture.view];
    BOOL isHorizontalGesture = fabs(velocity.y) <= fabs(velocity.x);

    if(isHorizontalGesture) {
        CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view];
        if(([self isPointContainedWithinLeftBezelRect:point] && self.leftDrawerViewController) ||
           ([self isPointContainedWithinRightBezelRect:point] && self.rightDrawerViewController)){
            if ([otherGestureRecognizer isKindOfClass:NSClassFromString([NSString stringWithFormat:@"UIScrollView%@", @"GestureRecognizer" ])]) {
                [_disabledGestures addObject:otherGestureRecognizer];
                otherGestureRecognizer.enabled = NO;
                return YES;
            }
        }
    }
    return NO;
}

And don't forget to re-enable the gesture in UIGestureRecognizerStateEnded and UIGestureRecognizerStateCancelled

JanHalozan commented 9 years ago

@farfromrefug I like your solution. A bit hacky but I don't think there is any other way. I do have a tiny improvement however: you don't need to save the reference to otherGestureRecognizer. Re-enabling it right after disabling does the trick since the scroll view pan recognizer sends the failure message right away.

My version of your inner if is this:

if ([otherGestureRecognizer isKindOfClass:NSClassFromString(@"UIScrollViewPanGestureRecognizer")])
{
    otherGestureRecognizer.enabled = NO;
    otherGestureRecognizer.enabled = YES;

    return YES;
}
farfromrefug commented 9 years ago

@Majster25 Thank you! Your solution is MUCH better and actually fixed a bug of my solution (a tap would disable the scrollview). Thanks again!

franchalo commented 9 years ago

is it possible to post the entire code on how you disabled your scrollview to enter - (BOOL)gestureRecognizer:(UIGestureRecognizer )gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer )otherGestureRecognizer

JanHalozan commented 9 years ago

No problem at all. In case you're wondering, the panGestureRecognizer is an ivar of the MMDrawerController class. I've just edited the setupGestureRecognizers method and stored a reference to the gesture recognizer. If you have any more questions feel free to ask.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if (gestureRecognizer != panGestureRecognizer || self.openSide != MMDrawerSideNone)
        return NO;

    const CGPoint velocity = [panGestureRecognizer velocityInView:gestureRecognizer.view];

    if (fabsf(velocity.y) > fabsf(velocity.x)) //If not a horizontal gesture return
        return NO;

    const CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view];

    if (([self isPointContainedWithinLeftBezelRect:point] && self.leftDrawerViewController) || ([self isPointContainedWithinRightBezelRect:point] && self.rightDrawerViewController))
    {
        if ([otherGestureRecognizer isKindOfClass:NSClassFromString(@"UIScrollViewPanGestureRecognizer")])
        {
            otherGestureRecognizer.enabled = NO;
            otherGestureRecognizer.enabled = YES;

            return YES;
        }
    }

    return NO;
}
farfromrefug commented 9 years ago

@Majster25 After implementing MGSwipeTableCell in my apps i can even say that the delegate method can be simplified. We "should" (must...) disable/enable the other gesture in all cases:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if (gestureRecognizer != self.panGesture || self.openSide != MMDrawerSideNone) {
        return NO;
    }
    CGPoint velocity = [self.panGesture velocityInView:self.panGesture.view];
    BOOL isHorizontalGesture = fabs(velocity.y) <= fabs(velocity.x);

    if(isHorizontalGesture) {
        CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view];
        if(([self isPointContainedWithinLeftBezelRect:point] && self.leftDrawerViewController) ||
           ([self isPointContainedWithinRightBezelRect:point] && self.rightDrawerViewController)){
            otherGestureRecognizer.enabled = NO;
            otherGestureRecognizer.enabled = YES;
            return YES;
        }
    }
    return NO;
}
mingming1222 commented 9 years ago

@farfromrefug Thank you very much !!! and @Majster25

lipeiran commented 9 years ago

hi,i find "CGPoint velocity = [self.panGesture velocityInView:self.panGesture.view];",velocity.x & y is always 0. anybody can help me? THX

lipeiran commented 9 years ago

@mingming1222,Please Help Me~

0x0078 commented 9 years ago

sorry...i dont no. 😂

发自我的 iPhone

在 2015年7月30日,19:19,lipeiran notifications@github.com 写道:

hi,i find "CGPoint velocity = [self.panGesture velocityInView:self.panGesture.view];",velocity.x & y is always 0. anybody can help me? THX

— Reply to this email directly or view it on GitHub.

idoan commented 9 years ago

"I've just edited the setupGestureRecognizers method and stored a reference to the gesture recognizer"

Just to clear the confusion to @JanHalozan 's great answer, just assign local variable pan to panGestureRecognizer that you defined as a property in setupGestureRecognizers .

You must also change isPointContainedWithRightBezelRect isPointContainedWithinRightBezelRect (change With to Within) to fix the error.

idoan commented 9 years ago

@farfromrefug is right. We must remove that last if condition for UIScrollViewPanGestureRecognizer, because when the transitionStyle is changed to pageCurl, this check doesn't work expectedly, since pageCurl calls UIPanGestureRecognizer .

qpwang commented 9 years ago

velocity.x & y is always 0.

+1

JanHalozan commented 9 years ago

Is this already somewhere in the implementation or in a PR? Otherwise I'll submit a new pull request.