簡體   English   中英

內部具有垂直UIScrollViews的水平UIScrollView - 如何在滾動外部水平視圖時阻止滾動內部滾動視圖?

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

無法找到解決方案。

我正在構建一個具有大滾動視圖的應用程序,具有分頁(水平)。 在這個滾動視圖中,有一個UIView網格,每個網格中都有一個UIScrollview,有垂直滾動視圖。

現在,關鍵是,當我分頁我的'大'滾動視圖時,有時觸摸會卡在網格的UIViews中的一個小滾動視圖中。

我不知道如何避免它 - 嘗試使用hitTest但仍然無法找到答案。

希望我很清楚......

謝謝你的幫助。

編輯:

這是更大的scrollview:

@implementation UIGridScrollView
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    self.pagingEnabled;
    return self;
}
@end

現在,對於這個UIGridScroll View,我添加了一個子視圖這個視圖:

@implementation UINoteView
{
IBOutlet UIScrollView *_innerScrollView; // this scrollview frame is in the size of the all UINoteView
}

- (void)awakeFromNib
{
    _innerScrollView.contentSize = CGSizeMake(_innerScrollView.frame.size.width, _innerScrollView.frame.size.height+50.0f);
}
@end

分頁效果很好,內部滾動視圖效果很好,但是當我分頁較大的音符視圖時,我的手指“卡在”_innerScrollView中的次數太多了。

謝謝!

@stanislaw,我剛試過你在iPhone設備上建議的解決方案。

我看到你的問題。

您的代碼確實可以防止偶爾滾動垂直視圖,但我相信不是同步手勢識別完成工作 - 注釋您為內部視圖提供的整個代碼,並使用外部滾動視圖的代碼進行以下修改:

@interface OuterHorizontalScrollView : UIScrollView ...
@property (weak) InnerVerticalScrollView *currentActiveView; // Current inner vertical scroll view displayed.
@end

@implementation OuterHorizontalScrollView
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (self.currentActiveView.dragging == NO) {
        self.currentActiveView.scrollEnabled = NO; // The presence of this line does the job
    }
    return YES;
}

- (void)scrollViewDidEndDragging:(PlacesScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    self.currentActiveView.scrollEnabled = YES; // This is very likely should be done for all subviews, not only a current.
}    
@end

你可以gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: UIScrollView並實現gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: ,允許滾動視圖的內置panGestureRecognizer與另一個滾動視圖的手勢識別器同時識別。

例:

//This is needed because the public UIScrollView headers
//don't declare the UIGestureRecognizerDelegate protocol:
@interface UIScrollView (GestureRecognition) <UIGestureRecognizerDelegate>
@end

@interface MyScrollView : UIScrollView

@end

@implementation MyScrollView

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if (gestureRecognizer == self.panGestureRecognizer) {
        return YES;
    } else if ([UIScrollView instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]) {
        //Note: UIScrollView currently doesn't implement this method, but this may change...
        return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];
    }
    return NO; //the default
}

@end

將此子類用於水平視圖或所有垂直滾動視圖都應該足夠了。

在嘗試以這種方式使用之后,您可能會發現您更喜歡默認行為。 允許兩個視圖同時滾動幾乎總是導致意外的垂直滾動,同時向左和向右滑動,這可能是刺激性的(大多數人不做完美的水平滑動手勢)。

我是這樣做的:

在垂直滾動視圖中使用shouldRecognizeSimultaneouslyWithGestureRecognizer (感謝@omz!)和自定義滑動手勢識別器(參見類似問題)

水平滾動UIScrollView與垂直平移手勢 ),我有以下設置:

@interface UIScrollView (GestureRecognition) <UIGestureRecognizerDelegate>
@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;
}

這段代碼有點hacky:它只允許滾動垂直滾動視圖,只有當它們的自定義滑動手勢被識別時(只有頂部或底部方向),所有其他手勢都傳遞給外部滾動視圖,而外部滾動視圖只允許任何手勢,如果沒有人正在拖動內部滾動視圖。

注意:滑動手勢也適用於慢速或微小滑動並不明顯,但確實如此(參見上面引用問題的評論)。

我覺得它可以更容易完成,也許我稍后會重構它。

無論如何,現在外部滾動工作完美 - 它水平滾動,沒有任何偶爾的內部滾動視圖垂直平移。

稍后更新:正如我之前所預料的那樣,我的解決方案確實包含了不必要的代碼:請參閱@burik的答案,而部分基於我的解決方案,它會從中獲取這些內容。

我對你的設置有點困惑,但你可能想看一下-[UIScrollView setDelaysContentTouches:] 在處理嵌套滾動視圖時,您可以使用它來添加一些優先級。

一旦我遇到這種情況,我就有以下工作要做。

從UIScrollView中對您的視圖進行子類化,您可以使用它。 在您的情況下,我可以看到您的UINoteView不是UIScrollView的子類,從ScrollView繼承它並從此類中刪除innerScrollView。

我認為使用velocity來確定滾動方向是一種更好的方法:

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
    CGPoint velocity = [gestureRecognizer velocityInView:gestureRecognizer.view];
    return fabs(velocity.y) > 3 * fabs(velocity.x);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM