iOS 8.4: Scroll view resets contentOffset with Voi

2020-06-20 12:41发布

问题:

With Voice Over enabled scroll views reset their preset contentOffset a second after view did appear. It happens on iOS 8.4 devices, no reproduction for 9.0. Looks some internal UIScrollViewAccessibility code forces scroll view to setContent: for zero when becoming focused. Didn't find any way to evade this.

Any thoughts?

Related code sample illustrates the bug. Just create a view with collection view, create a cell with reuse id "Cell" and put a label on it.

@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
@property (nonatomic, weak) IBOutlet UICollectionView *collectionView;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.collectionView.backgroundColor = [UIColor clearColor];
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.collectionView reloadData];
    //set there 4 seconds and bug will disappear
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:5 inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    });
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSLog(@"Why you scroll second time?");
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return self.view.bounds.size;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 10;
}
- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    UILabel *label = (UILabel*)cell.contentView.subviews[0];
    label.text = @(indexPath.item + 1).stringValue;
    if (indexPath.item == 5) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{           UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, label);
        });
    }
    return cell;
}
@end

回答1:

It's doing this intentionally. If users are using swipe gestures to navigate. If you navigate into a scroll view, the first element in the view should be focused. For sighted VoiceOver users, obviously not scrolling up to the top would be jarring, as potentially your focus rectangle could be off screen. This is a feature, not a bug.