UICollectionView:激活,滚动到第一响应者并将其分配给远程单元

时间:2013-07-02 21:01:13

标签: ios cocoa-touch uiscrollview uicollectionview uicollectionviewcell

我在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];
    });
}

1 个答案:

答案 0 :(得分:1)

我对UITableView进行了类似的挑战:滚动到尚未显示​​的单元格,并在目标单元格中​​可见时将第一响应者分配给目标单元格中​​的UITextField。这是我如何处理这个的简化描述。我想这种方法适用于UICollectionView,但我对集合视图没有多少经验。

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

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

    我的实际实现有点专门用于与我的表视图关联的视图模型,并封装在几个类中并使用一些KVO,但我想避免这种情况,并专注于上述描述中所需的最小逻辑。 / p>