4

我在 a 中有一个UICollectionViewCell可以接收第一响应者状态的文本字段。该单元格当前在屏幕上不可见,我想根据从UISegmentedControl. 此控件有两个段……点击第二个段应滚动到UICollectionView. 发生这种情况后,应该以编程方式选择单元格,然后该单元格内的文本字段应该获得第一响应者状态并调出键盘。

现在发生的事情(在我的操作方法中,来自分段控件的值更改)是调用-[UICollectionView selectItemAtIndexPath:animated:scrollPosition:]根本没有滚动到它(我正在使用UICollectionViewScrollPositionTop; 也可能是“ …None”)。如果我手动按下列表,则确实选择了单元格(在该状态下它的背景颜色较深),但文本字段肯定没有第一响应者状态。

为了解决滚动问题,我已经能够确定单元格在列表中的位置,并滚动到单元格的内容偏移量(我也在scrollRectToVisible这里使用过)。然后我手动选择它(以及告诉代理也触发其适当的方法,单元格的文本字段获得第一响应者状态)。

- (void)directionSegmentedControlChanged:(UISegmentedControl *)sender {
    NSIndexPath *path = [NSIndexPath indexPathForItem:0 inSection:sender.selectedSegmentIndex];
    UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:path];
    [self.collectionView setContentOffset:attributes.frame.origin animated:YES];
    [self.collectionView selectItemAtIndexPath:path animated:NO scrollPosition:UICollectionViewScrollPositionNone];
    [self.collectionView.delegate collectionView:self.collectionView didSelectItemAtIndexPath:path];
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    BDKCollectionViewCell *cell = (BDKCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
    [cell.textField becomeFirstResponder];
}

这里的问题是它所看到的单元格-[collectionView:didSelectItemAtIndexPath:]是 nil,因为当方法被触发时它不在集合视图的可见单元格集中。

解决这个问题的最佳方法是什么?我尝试将滚动代码扔到一个[UIView animateWithDuration:animations:completion:]块内,并在完成后分配第一响应者,但是以这种方式手动为集合视图设置动画会忽略加载任何应该滚动过去的单元格。有任何想法吗?


更新:非常感谢@Esker,他建议我在使用 Grand Central Dispatch 延迟后执行“焦点选择”操作。我的解决方案最终看起来像这样。

- (void)directionSegmentedControlChanged:(UISegmentedControl *)sender {
    NSIndexPath *path = [NSIndexPath indexPathForItem:0  inSection:sender.selectedSegmentIndex];

    UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:path];
    [self.collectionView setContentOffset:attributes.frame.origin animated:YES];

    dispatch_time_t startAfter = dispatch_time(DISPATCH_TIME_NOW, 0.28 * NSEC_PER_SEC);
    dispatch_after(startAfter, dispatch_get_main_queue(), ^{
        [self.collectionView selectItemAtIndexPath:path animated:NO scrollPosition:UICollectionViewScrollPositionNone];
        [self collectionView:self.collectionView didSelectItemAtIndexPath:path];
    });
}
4

1 回答 1

1

我遇到了类似的挑战UITableView:滚动到一个尚不可见的单元格,并UITextField在目标单元格可见后将第一响应者分配给目标单元格。这是我如何处理此问题的简化描述。我想这种方法可以与 a 一起使用UICollectionView,但我对集合视图没有太多经验。

  1. 如果所需的单元格/文本字段当前可见,请立即发送它becomeFirstResponder,并在需要时滚动到该单元格。
  2. 否则,在视图控制器或类似的类中设置一个属性,指示文本字段需要焦点,以及哪个需要焦点
  3. 告诉表视图/集合视图滚动到所需的索引路径
  4. collectionView:cellForItemAtIndexPath:中,您可以尝试检查该属性以查看给定的文本字段是否indexPath需要获得焦点,如果是,请becomeFirstResponder立即发送,但我发现如果单元格滚动到视图中,这将不起作用,大概是因为在此时,当您配置新单元格时,它实际上还没有在视图层次结构中。所以我添加了一个检查,如果此时becomeFirstResponder返回NO,我会在延迟后重试:
dispatch_after(someDelay, dispatch_get_main_queue(), ^(void){
    [self getFocus:textField];
});

getFocus方法将发送becomeFirstResponder到文本字段并清除跟踪哪个文本字段需要焦点的属性。

我的实际实现在某种程度上专门针对与我的表视图关联的视图模型,并封装在几个类中并使用了一些 KVO,但我想避免这种情况并专注于上面描述中所需的最低逻辑。

于 2013-07-03T01:24:16.717 回答