Horizontal UIScrollView having vertical UIScrollViews inside - how to prevent scrolling of inner scroll views when scrolling outer horizontal view?

后端 未结 6 622
天涯浪人
天涯浪人 2021-02-09 18:12

couldn\'t find a solution for that.

I am building an app, with big scroll view, who has paging (Horizontal). Inside this scroll view, there is a grid of UIView\'s, and a

6条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-02-09 18:59

    Here is how I have done it:

    Using shouldRecognizeSimultaneouslyWithGestureRecognizer (thanks @omz!) and custom swipe gesture recognizer in vertical scroll views (see the similar question

    Horizontal scrolling UIScrollView with vertical pan gesture), I have the following setup:

    @interface UIScrollView (GestureRecognition) 
    @end
    
    @interface OuterHorizontalScrollView : UIScrollView ...
    @property (weak) InnerVerticalScrollView *currentView; // Current inner vertical scroll view displayed.
    @end
    
    @implementation OuterHorizontalScrollView
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
        if (self.currentActiveView.placeVerticalScrollView.dragging == NO) {
            self.currentActiveView.placeVerticalScrollView.scrollEnabled = NO;
            return YES;
        } else {
            return NO;
        }
    }    
    @end
    
    @interface InnerVerticalScrollView : UIScrollView...
    @property UISwipeGestureRecognizer *swipeGestureRecognizer;
    @end
    
    @implementation InnerVerticalScrollView
    - (id)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
            ...
            self.swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeGesture:)];
            self.swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp;
            [self addGestureRecognizer:self.swipeGestureRecognizer];
        }
    
        return self;
    }
    
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
        if (gestureRecognizer == self.panGestureRecognizer && self.scrollEnabled == YES) {
            return YES;
        } else if (gestureRecognizer == self.swipeGestureRecognizer) {
            return YES;
        } else {
            self.scrollEnabled = NO;
        }
    
        return NO;
    }
    
    - (void)handleSwipeGesture:(UIGestureRecognizer *)sender {
        self.scrollEnabled = YES;
    }
    
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {    
        return YES;
    }
    

    This code is a bit hacky: it allows scrolling of vertical scroll views only if their custom Swipe gesture is recognized (only top or bottom directions), all other gestures are passed to outer scroll view which in its turn allows any gestures only if no one of inner scroll views are being dragged.

    Note: it was not obvious that swipe gesture works for slow or tiny swipes too, but it does (see also comments to quoted question above).

    I feel like it could be accomplished easier and maybe I will refactor it later.

    Anyway, now outer scroll works perfectly - it scrolls horizontally without any occasional vertical pans of inner scroll views.

    LATER UPDATE: As I expected before, my solution did contain unnecessary bits of code: see the answer by @burik, while being partially based on my solution, it takes these bits out of it.

提交回复
热议问题