I have a text box inside a UICollectionViewCell that can receive the status of the first responder. The cell is not currently displayed on the screen, and I want to scroll to the cell based on the button click with the UISegmentedControl . There are two segments for this control ... and the hit in the second segment should scroll to the first cell in the 2nd part of the UICollectionView . After that, the cell should be selected programmatically, and then the text field inside this cell should receive the status of the first responder and call the keyboard.
What happens now (inside my action method from changing the value from a segmented control) is that the call -[UICollectionView selectItemAtIndexPath:animated:scrollPosition:] does not scroll at all (and I use UICollectionViewScrollPositionTop ; it may also be " …None "). If I print the list manually, the cell will actually be selected (in this state there will be a darker background color), but the text field, of course, does not have the status of the first responder.
To fix the scroll problem, I was able to determine the position of the cell in the list and scroll to offset the contents of the cell ( scrollRectToVisible was also used scrollRectToVisible ). Then I will manually select it (and also tell the delegate to start the corresponding method, where the text field of the cell receives the status of the first responder).
- (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 that is visible in -[collectionView:didSelectItemAtIndexPath:] is nil because it is not in the visible cell of the collection's collection view when the method starts.
What is the best way to solve this problem? I tried to throw my scroll codes inside the [UIView animateWithDuration:animations:completion:] block, and was assigned the first to the responder after completion, but I manually neglected the collection view in this way to load any of the cells that should be scrolled by the past. Any ideas?
Update : many thanks to @Esker, who suggested that I simply do a “focus selection” after the delay using Grand Central Dispatch. My decision turned out to be 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]; }); }