【问题标题】:UIPickerView is not scrolling when added to UIScrollView!UIPickerView 添加到 UIScrollView 时不滚动!
【发布时间】:2011-01-25 12:33:40
【问题描述】:

我已将 UIPickerView 添加到 UIScrollView 但现在 UPickerView 不滚动。当我将它添加到 self.view 时,它会平滑滚动。 这是我的代码

monthsArray = [[NSArray alloc] initWithObjects:@"Jan",@"Feb",@"Mar",@"Apr",@"May",@"Jun",@"Jul",@"Aug",@"Sep",@"Oct",@"Nov",@"Dec",nil];

UIPickerView *objPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(185,350,100,100)];
    objPickerView.userInteractionEnabled=YES;
    objPickerView.delegate = self;
    objPickerView.showsSelectionIndicator = YES; 
    [objScrollView addSubView:objPickerView];

我已经包含了委托及其方法。看看这个问题。提前致谢。
如果我不清楚,请告诉我。

【问题讨论】:

  • 可以使用 Swift 3 更新此解决方案

标签: iphone


【解决方案1】:

我使用 UIPickerView 的一个子类来达到同样的目的,但我的要简单得多:

@implementation ScrollablePickerView

- (UIScrollView *)findScrollableSuperview {

    UIView *parent = self.superview;
    while ((nil != parent) && (![parent isKindOfClass:[UIScrollView class]])) {
        parent = parent.superview;
    }
    UIScrollView* scrollView = (UIScrollView *)parent;

    return scrollView;
}

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event {
    UIScrollView* scrollView = [self findScrollableSuperview];

    if (CGRectContainsPoint(self.bounds, point)) {
        scrollView.canCancelContentTouches = NO;
        scrollView.delaysContentTouches = NO;
    } else {
        scrollView.canCancelContentTouches = YES;
        scrollView.delaysContentTouches = YES;
    }

    return [super hitTest:point withEvent:event];
}

@end

像魅力一样工作 - 至少对我而言。

【讨论】:

  • Erm... 这个项目目前有点被放弃了,我也没有 Swift 测试平台。请不要指望我暂时对此进行更新。对不起。
【解决方案2】:

来自 UIScrollView 类文档:

重要提示:您不应在 UIScrollView 对象中嵌入 UIWebView 或 UITableView 对象。如果这样做,可能会导致意外行为,因为这两个对象的触摸事件可能会混淆和错误处理。

他们在那里没有提到 UIPickerView,但我想知道它是否应该被添加到该列表中。它与其他的共同点是使用触摸来滚动内容。

【讨论】:

    【解决方案3】:

    我想这可能会解决您的问题(请务必检查 cmets):

    http://www.alexc.me/uiscrollview-and-uidatepicker/153/

    基本上,您必须在滚动视图上将 DelaysContentTouches 和 CanCancelContentTouches 设置为 NO,因为它会从选取器中窃取触摸事件。

    【讨论】:

      【解决方案4】:

      UIPickerView 根本不是为滚动或移动而设计的。您应该放置一些文本字段,并在用户点击它时显示 UIPickerView。

      【讨论】:

      • im:我想你错过了数组。我添加了数组内容作为每一行的标题。现在你能告诉我如何在没有 scrollibf UIPickerView 的情况下选择“Dec”吗?
      • 选择器本身会进行滚动。如果有的话,滚动视图可以将选择器作为一个整体移动到屏幕上。
      • @Axel:“选择器本身会滚动”我知道这一点,但是当我将它添加到 UIScrollView 时它不会滚动。
      【解决方案5】:

      嵌套在 UIScrollView 中的 UIPickerView 遇到了类似的问题,并通过子类化 UIPickerView 解决了这个问题。对 DelaysContentTouches/CanCancelContentTouches 的更改没有帮助,这里的其他“答案”基本上说“不要这样做”——好吧,那根本不是答案!它可以完成,您可以让选择器在滚动视图中运行。

      我回答了以下关于子类化 UIPickerView 的问题,包括最后一些可能对您有所帮助的代码:

      Responding to touchesBegan in UIPickerView instead of UIView

      【讨论】:

        【解决方案6】:

        我也遇到过类似的问题。我有一个 UIPickerView,我通过应用转换(效果很好)将它变成水平,但是在滚动视图内部,滚动只能在左侧工作。

        我认为正在发生的事情是 UIPicker 查找它的父链以查看是否有任何手势识别器,并将自己设置为委托,因此它可以禁用手势识别在链的上游以在其边界内进行触摸,并且虽然变换改变了视觉边界,但它并没有改变框架,它是在寻找原始边界内的触摸。

        如果不是这样,您可以使用它来防止滚动视图窃取您的触摸。

        我想我要切换到自定义 UISCrollView,而不是转换后的 UIPickerView。

        【讨论】:

          【解决方案7】:

          在 iOS 11 和 iOS 12 上,当 UIScrollView 已经被拖动时更改 canCancelContentTouchesdelaysContentTouches 并没有帮助。所以我通过在scrollView.panGestureRecognizer 接收到它们之前拦截一些触摸来进行破解。

          这是 Swift 4 代码。也许我们可以更优雅地检查触摸是否在选择器内部。但是效果很好。

          public class TableView: UITableView {
          
              /// Check if view is a picker's subview
              private func isInPickerView(_ view: UIView) -> Bool {
                  var prev: UIView? = view
                  while prev != nil {
                      if prev is UIPickerView ||  prev is UIDatePicker {
                          return true
                      }
                      prev = prev?.superview
                  }
                  return false
              }
          
              // UITableView is already UIGestureRecognizerDelegate internally, 
              // so we just need to overwrite 1 method here
              public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, 
                                            shouldReceive touch: UITouch) -> Bool {
                  // we don't care about any recognizers except self.panGestureRecognizer
                  guard gestureRecognizer == panGestureRecognizer else {
                      return true
                  }
                  // if touch is inside picker - we don't pass this touch 
                  // to panGestureRecognizer
                  let location = touch.location(in: self)
                  if let view = self.hitTest(location, with: nil), isInPickerView(view) {
                      return false
                  }
                  return true
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-01-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多