滚动时读取PickerView的位置

时间:2011-03-08 20:06:48

标签: iphone objective-c uitableview

我有一个带自定义单元格的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) 

我可以尝试什么其他想法来获得这个价值?

6 个答案:

答案 0 :(得分:3)

我想 - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
随着 [pickerView selectedRowInComponent:0]);
正是你想要的。 :)

答案 1 :(得分:2)

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

你必须做一些实验才能做到正确。拾取器似乎要求一行或两行尚未可见,可能是为了保持滚动顺畅。在我的测试中,一个显示5行的选择器,在选择器要求的行和中心之间似乎有大约3行的差异。您显然还必须跟踪旋转方向(向上或向下),并且在调用-pickerView:didSelectRow:inComponent:之前,您将无法确定是否选择了第一行或最后两行或三行。

答案 2 :(得分:0)

我认为这很有趣。我想用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和杆架/中心属性怎么样?

答案 3 :(得分:0)

框架不会因为单元格没有移动而改变。它的一个超级视图是,细胞随身携带。要找出父UIPickerView中的单元格坐标,请尝试以下操作:

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

结果矩形将位于thePicker的坐标系中,然后您可以通过以下简单测试找出它是否在中间:

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

答案 4 :(得分:0)

只是一个简单的想法,但你可以通过UIPickerView添加一个UIScrollView(透明,其contentView与组件数一样高)。

然后收听UIScrollViewDelegate方法以获取所需的实时滚动数据。

棘手的部分是将滚动条中的触摸事件传递给拾取器,以便它按预期运行。

答案 5 :(得分:0)

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

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

您可以通过将UIPickerView的行数设置为0来完成此操作,并将透明tableView放在UIPickerView上。你的tableView将保存实际的单元格,并且由于UITableView继承自UIScrollView,你可以获得有关滚动的事件,只需检查选择行当前的UITableViewCell。