【问题标题】:UIScrollView inside UIScrollViewUIScrollView 里面的 UIScrollView
【发布时间】:2013-03-04 11:15:34
【问题描述】:

我有一个UIScrollView,里面有另一个UIScrollView。它们都水平滚动并具有pagingEnabled = YES。 假设我开始滚动内部滚动视图并到达最右边的边界。如果我继续在其中滚动,则外部 scrollView 开始移动。我需要避免这种情况。内视图应以橡皮筋效果跳跃,外视图应保持原位。

希望很清楚,但这里有一个草图:

我试过这样设置outerView.scrollEnabled = NO;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    outerView.scrollEnabled = NO;
}

,它完全按照我的需要工作,如果只是在 innerView 中滚动。 OuterView 不再滚动。但是如果我想再次滚动outerView,我必须在某处将scrollEnabled 设置回YES。 我在这里尝试过:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    outerView.scrollEnabled = YES;
}

,但是我遇到了同样的问题:在到达 innerView 的最右侧边界后,outerView 滚动而不是 innerView 以橡皮筋效果跳转。

有什么解决问题的建议吗?

【问题讨论】:

  • 在您的滚动视图委托方法中,它看起来不像您检查哪个 scrollviewViewBeginDragging 和哪个 scrollViewDidEndDecelerating。我不完全了解您的需求,但这显然是错误的。
  • 尝试在每个滚动视图上设置标签然后检查if(scrollview.tag == 1)
  • @mkral:我对这些视图也有不同的代表,所以我不需要检查参数。

标签: ios ipad cocoa-touch uiscrollview uikit


【解决方案1】:

更新

此解决方案始终有效:

@implementation InnerScrollViewController <UIScrollViewDelegate, UIGestureRecognizerDelegate>

- (void)viewDidLoad
{
    UISwipeGestureRecognizer*   swipeGesture = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)] autorelease];
    swipeGesture.delegate = self;
    [self.view addGestureRecognizer:swipeGesture];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    _outerScrollView.scrollEnabled = NO;
    return YES;
}

- (void)handleSwipe:(UIGestureRecognizer*)gestureRecognizer
{

}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{   
    _outerScrollView.scrollEnabled = NO;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate)
    {
        _outerScrollView.scrollEnabled = YES;
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    _outerScrollView.scrollEnabled = YES;
}

@end

------------------------------------------ ---------------------------------------

旧答案:并不总是有效

这是我解决问题的方法:

@implementation InnerView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.delaysContentTouches = NO;
    }
    return self;
}

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
    return NO;
}

据我了解,self.delaysContentTouches = NO; 使所有事件立即传递,- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view 阻止响应链传递这些事件。

【讨论】:

  • 我也有同样的问题。我尝试了您的解决方案,但这样做会阻止 InnerView 的子视图免受任何触摸事件的影响。我在内部滚动视图中有几个按钮作为子视图。滚动工作正常,但按钮不再可点击。您还有其他解决方案吗?
  • @AlexeyGolikov:是的,这个解决方案非常棘手,我不确定它是否适用于所有情况。我认为,WWDC 2013 会议“探索 iOS 7 上的滚动视图”(developer.apple.com/wwdc/videos/index.php?id=217)会有所帮助,即 Demo,从 11:00 开始。不幸的是,我很晚才看到这个视频,然后我问了这个问题并没有尝试实现它。
  • 谢谢你,@anastasia。不幸的是,视频对我没有帮助。仍在寻找解决方案。
  • 我认为这个解决方案的一个问题是它破坏了良好的设计,因为子视图引用了它的父视图。在简单的架构中可能还可以,但在更复杂的架构中,就不是那么好了。
  • @DavidJames 当然,它不一定有对父视图的引用,您可以发送适当的通知并处理它,作为一种选择。这个想法是展示最简单的工作示例。
【解决方案2】:

通过以下方式修改您的方法:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    if(scrollView == innerView)
        outerView.scrollEnabled = NO;
    else
        outerView.scrollEnabled = YES;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    if(scrollView == innerView)
    {
         if(innerView.contentOffset.x + innerView.frame.size.width == innerView.contentSize.width)
         {
              outerView.scrollEnabled = NO;
         }
         else
         {
              outerView.scrollEnabled = YES;
         }
    }
}

【讨论】:

  • 谢谢,但问题是scrollView是否有scrollEnabled == NO;比 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 不再需要它了。所以我不能在这个方法中将 scrollEnabled 设置回 YES。
【解决方案3】:

我也有类似的问题。我找到了解决方案,但它仅适用于 innerScrollView.bounces = NO

@interface PageCtrl ()
    @property (weak, nonatomic) IBOutlet UIScrollView *innerScrollView;
    @property(nonatomic) UIPanGestureRecognizer *panLockScroll;
@end

@implementation PageCtrl
- (void)viewDidLoad {
    // ...
    self.innerScrollView.delegate = self;   

    self.innerScrollView.bounces = NO;   // disable bounces!

    self.panLockScroll = [[UIPanGestureRecognizer alloc]initWithTarget:self action:nil];
    self.panLockScroll.delegate = self;
    [self.innerScrollView addGestureRecognizer:self.panLockScroll];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer{
    if( gestureRecognizer == self.panLockScroll && 
        otherGestureRecognizer == self.innerScrollView.panGestureRecognizer ){
        return YES;
    }
    return NO;
}

@end

【讨论】:

    【解决方案4】:

    这对我很有效:

    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
      outerScrollView.scrollEnabled = NO;
    }
    
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
      [NSTimer scheduledTimerWithTimeInterval:0.3
                                         target:[NSBlockOperation blockOperationWithBlock:^{ outerScrollView.scrollEnabled = YES; }]
                                       selector:@selector(main)
                                       userInfo:nil
                                        repeats:NO];
    }
    

    记得在你的类声明中采用 UIScrollViewDelegate 并将 innerScrollView 的委托设置为 self(不要分配 outerScrollView 的委托)

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-08
      相关资源
      最近更新 更多