【问题标题】:Read position of UIPickerView while scrolling?滚动时读取 UIPickerView 的位置?
【发布时间】:2011-03-08 20:06:48
【问题描述】:

我有一个带有自定义单元格的 UIPickerView。每时每刻,我都想知道哪个单元格位于中心位置(在有色选择指示器后面)。 UIPickerView 委托方法

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

确实提供此信息,但仅在选择器视图停止后提供。我正在寻找的是一种在选择器视图仍在旋转且尚未停止时检索当前“选定”单元格的方法。

作为一种解决方法,我尝试通过 KVO 并注册每个单元格的视图更改:

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    .
    .
    [cell addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}

我确实收到了对observeValueForKeyPath:ofObject:change:context: 的回调,但是无论我向上还是向下滚动选择器视图,收到的值似乎总是相同的:

2011-03-09 08:00:34.429 Project[35069:207] Frame: x=2.00, y=-13.00
2011-03-09 08:00:34.430 Project[35069:207] Location: x=4.00, y=-26.00
2011-03-09 08:00:34.430 Project[35069:207] Change: {
    kind = 1;
    new = "NSRect: {{2, -13}, {118, 70}}";
    old = "NSRect: {{2, -13}, {118, 70}}";
}
2011-03-09 08:00:34.431 Project[35069:207] Frame: x=2.00, y=-13.00
2011-03-09 08:00:34.431 Project[35069:207] Location: x=4.00, y=-26.00
2011-03-09 08:00:34.432 Project[35069:207] Change: {
    kind = 1;
    new = "NSRect: {{2, -13}, {118, 70}}";
    old = "NSRect: {{2, -13}, {118, 70}}";

(Location coordinates are in window frame) 

还有什么我可以尝试获得该价值的想法吗?

【问题讨论】:

    标签: iphone objective-c uitableview


    【解决方案1】:

    我认为的方法:

    - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view`
    

    与:

    [pickerView selectedRowInComponent:0]);
    

    正是你想要的。

    【讨论】:

      【解决方案2】:

      您可以使用您的选择器委托的-pickerView:titleForRow:forComponent: 方法让您很好地了解选择器的轮子在哪里。当您向一个方向或另一个方向滚动时,选择器将向其代表询问一行的标题(或视图)。轮子“中心”与选择器要求的行之间的行数取决于行高,但您可能知道那是什么。

      您必须进行一些试验才能做到正确。选择器似乎要求一两行尚不可见,也许是为了保持滚动流畅。在我使用显示 5 行的选择器的测试中,选择器要求的行与中心之间似乎存在 3 行差异。您显然还必须跟踪旋转方向(向上或向下),并且在调用 -pickerView:didSelectRow:inComponent: 之前,您不会知道是选择了前两行还是最后两行或三行。

      【讨论】:

      • 我在其他地方看到过这个想法,但似乎有点不安全。您永远不知道将准确预加载多少视图。该数字可能在不同的 iOS 版本中有所不同,也可能取决于设备的内存可用性。我查阅了文档,但找不到这方面的任何规定。
      • 绝对不能保证,正如我上面提到的,该技术并非没有缺陷。我绝对建议进行彻底的测试。不过,除了滚动您自己的选择器视图之外,我认为这是您最接近实时通知选择器更改的方式。
      • 我这样做了,在这里我检查每个更改是否是连续的,因为 pickerView:titleForRow:forComponent: 以随机方式预取行,所以我将旧行保留在某处并仅在它是一上一下:~if (row == self.oldrow + 1 || row == self.oldrow - 1)~
      【解决方案3】:

      我觉得这很有趣。我想用 UIPicker 做类似的事情,但还没有深入研究。

      UIDatePicker 实际上是这样做的,您可以在中午左右拖动时间,即使手指尚未从屏幕上抬起,它也会切换 AM/PM(它不应该称为“didSelectRow”)。

      UIDatePicker 实际上是 UIControl 的子类,而不是 UIPickerView 之类的 UIView。因此,UIDatePicker 可能正在观察所有 UIControlEvents 来执行此操作。

      观察 -pickerView:titleForRow:forComponent 现在可能有效,但是如果以后行为发生变化(即缓存行为,即)发生变化,这将中断...

      一个建议是在中心属性上尝试 KVO,而不是框架。

      Edit1:顺便问一下,你的 observeValueForKeyPath 方法怎么样?

      Edit2:经过进一步研究,似乎大部分 UIKit 都不符合 KVO。
      看到这个答案 - Key value Observing during UIView Animations

      因此,似乎唯一的选择是在视图可见时继续对视图的值进行轮询。无论何时,forloop 和杆框架/中心属性如何?

      【讨论】:

        【解决方案4】:

        框架没有改变,因为单元格没有移动。它的超级视图之一是,并且单元格与它一起携带。要计算父单元UIPickerView 中的单元格坐标,请尝试以下操作:

        CGRect theApparentRect = [theCell convertRect: theCell.bounds toView: thePicker];
        

        生成的矩形将在thePicker的坐标系中,然后您可以通过以下简单测试确定它是否在中间:

        CGPoint middleOfThePicker = CGPointMake
        (
            CGRectGetMidX(thePicker.bounds),
            CGRectGetMidY(thePicker.bounds)
        );
        Boolean isInMiddle = CGRectContainsPoint(theApparentRect, middleOfThePicker);
        

        【讨论】:

        • 我已经在使用框架的原点进行此操作。不要认为我改变边界或框架的原点有什么区别吗?
        • 不,尽管单元格的原点可能与容器视图的可见边界对齐,也可能不对齐。试试完整的矩形看看?
        【解决方案5】:

        只是一个快速的想法,但是您可以在 UIPickerView 上添加一个 UIScrollView(透明的,内容视图与组件的数量一样高。)。

        然后监听 UIScrollViewDelegate 方法来获取你需要的实时滚动数据。

        棘手的部分是将触摸事件从滚动条传递到选择器,以便它按预期运行。

        【讨论】:

          【解决方案6】:

          UIPickerView 的问题是您为单元格设置的视图实际上是子视图。 UIPickerView 由各种 imageView、一个 TableView 和一个选择线构建而成。 您在使用 viewForRow 时提供的视图作为 tableView 单元格的子视图插入,因此它们的框架永远不会改变。 唯一改变的框架是实际 tableView 单元格的框架,您当然无法访问。

          一种可能的解决方案是简单地将 UIPickerView 的 tableView 替换为您自己的。

          您可以通过将 UIPickerView 的行数设置为 0 来实现,并在 UIPickerView 上放置一个透明的 tableView。您的 tableView 将保存实际的单元格,并且由于 UITableView 继承自 UIScrollView,因此您可以获取有关滚动的事件并简单地检查哪个 UITableViewCell 当前位于选择行下方。

          【讨论】:

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