[英]UICollectionView: activating, scrolling to, and assigning first responder to distant cell
I've got a text field inside of a UICollectionViewCell
that can receive first-responder status. 我在
UICollectionViewCell
中有一个文本字段,可以接收第一响应者状态。 The cell currently isn't visible on-screen, and I want to scroll to the cell based off of a button hit from a UISegmentedControl
. 当前在屏幕
UISegmentedControl
不到单元格,我想根据UISegmentedControl
中的按钮滚动到单元UISegmentedControl
。 There's two segments to this control… and a hit to the second segment should scroll to the first cell in the 2nd section of the UICollectionView
. 这个控件有两个段......对第二个段的命中应该滚动到
UICollectionView
的第二个部分中的第一个单元格。 After this happens, the cell should get selected programatically, and then the text field inside of that cell is supposed to get first responder status and bring up the keyboard. 发生这种情况后,应该以编程方式选择单元格,然后该单元格内的文本字段应该获得第一响应者状态并调出键盘。
What's happening now (inside my action method from a value change from the segmented control) is that a call to -[UICollectionView selectItemAtIndexPath:animated:scrollPosition:]
isn't scrolling to it at all (and I'm using UICollectionViewScrollPositionTop
; may as well be " …None
"). 现在发生的事情(在我的动作方法中,来自分段控件的值更改)是调用
-[UICollectionView selectItemAtIndexPath:animated:scrollPosition:]
根本没有滚动到它(我正在使用UICollectionViewScrollPositionTop
;可能是好吧“ …None
”)。 If I thumb down the list manually, the cell is indeed selected (it gets a darker background color in that state), but the text field certainly doesn't have first responder status. 如果我手动向下滑动列表,则确实选择了单元格(在该状态下它会获得较暗的背景颜色),但文本字段肯定没有第一响应者状态。
To fix the scroll problem, I've been able to ascertain the position of the cell in the list, and scroll to the cell's content offset (I've also used scrollRectToVisible
here). 为了解决滚动问题,我已经能够确定列表中单元格的位置,并滚动到单元格的内容偏移量(我在这里也使用了
scrollRectToVisible
)。 Then I manually select it (as well as telling the delegate to fire its appropriate method as well, where the cell's text field gains first responder status). 然后我手动选择它(以及告诉委托也启动它的适当方法,单元格的文本字段获得第一响应者状态)。
- (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];
}
The problem here is that the cell as it's seen in -[collectionView:didSelectItemAtIndexPath:]
is nil, because it's not in the visible cell set of the collection view when the method gets fired. 这里的问题是,在
-[collectionView:didSelectItemAtIndexPath:]
中看到的单元格是nil,因为当方法被触发时,它不在集合视图的可见单元格集中。
What's the best way to solve this? 解决这个问题的最佳方法是什么? I've tried tossing my scrolling code inside of a
[UIView animateWithDuration:animations:completion:]
block, and assigned first responder upon completion there, but manually animating the collection view in this manner neglects to load any of the cells that should be scrolled past. 我已经尝试在
[UIView animateWithDuration:animations:completion:]
块中抛出我的滚动代码,并在完成后分配第一个响应者,但是以这种方式手动动画集合视图忽略了加载应该滚动的任何单元格过去。 Any ideas? 有任何想法吗?
Update : many thanks to @Esker, who suggested I simply perform the "focus selection" action after a delay using Grand Central Dispatch. 更新 :非常感谢@Esker,他建议我在使用Grand Central Dispatch延迟后执行“焦点选择”操作。 My solution ended up looking like this.
我的解决方案最终看起来像这样。
- (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];
});
}
I had a similar challenge with a UITableView
: scrolling to a cell that was not yet visible, and assigning first responder to a UITextField
within the target cell once it was visible. 我在
UITableView
遇到了类似的挑战:滚动到一个尚未可见的单元格,并在目标单元格中可见时将第一个响应者分配给目标单元格中的UITextField
。 Here's a simplified description of how I handle this. 这是我如何处理这个的简化描述。 I imagine this approach could work with a
UICollectionView
, but I don't have much experience with collection views. 我想这种方法可以使用
UICollectionView
,但我对集合视图没有太多经验。
becomeFirstResponder
, and scroll to the cell if desired. becomeFirstResponder
,并根据需要滚动到该单元格。 collectionView:cellForItemAtIndexPath:
, you could try to check that property to see if a text field at the given indexPath
needs to get focus, and if so, send it becomeFirstResponder
immediately, but I found this won't work if the cell is scrolling into view, presumably because at this point, when you're configuring the new cell, it's not yet actually in the view hierarchy. collectionView:cellForItemAtIndexPath:
,您可以尝试检查该属性以查看给定indexPath
处的文本字段indexPath
需要获得焦点,如果是,请立即将其发送到becomeFirstResponder
,但我发现如果单元格正在滚动则不起作用进入视图,大概是因为此时,当您配置新单元格时,它实际上还不在视图层次结构中。 So I added a check, if becomeFirstResponder
returns NO
at this point, I try again after a delay: becomeFirstResponder
返回NO
,我会在延迟后再试一次: dispatch_after(someDelay, dispatch_get_main_queue(), ^(void){
[self getFocus:textField];
});
The getFocus
method will both send becomeFirstResponder
to the text field and clear that property that tracks which text field needs focus. getFocus
方法都会将becomeFirstResponder
发送到文本字段,并清除跟踪哪个文本字段需要关注的属性。
My actual implementation is somewhat specialized for the view model associated with my table view, and encapsulated in a couple of classes and using some KVO, but I wanted to avoid that and focus on the minimum required logic in the description above. 我的实际实现有点专门用于与我的表视图关联的视图模型,并封装在几个类中并使用一些KVO,但我想避免这种情况,并专注于上面描述中所需的最小逻辑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.