Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIScrollView Not scrolling in iOS11

I have created a UIScrollView in code and it works in iOS10. I updated my Xcode today and it is no longer scrolling in iOS11 (simulator is iOS11 and does not work; physical iPad is still iOS10 and works).

User can add subviews when they want. When its the first subview, I anchor it to the left side, top and bottom of the scroll view. Then I anchor the right side of the subview to the right side of the scroll view which gives the contentSize its size and so it knows it needs to enable scrolling

UIScrollView *scrollViewMain = [UIScrollView new];
scrollViewMain.delegate = self;
scrollViewMain.backgroundColor = [UIColor greenColor];
scrollViewMain.translatesAutoresizingMaskIntoConstraints = NO;
scrollViewMain.directionalLockEnabled = YES;
self.scrollViewMain = scrollViewMain;

... // other code

if (self.countPlayers == 1) {
    [self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[playerCardView(400)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
    [self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[playerCardView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];

    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeRight multiplier:1 constant:10];

    self.constraintScrollViewRight = constraint;

    [self.scrollViewMain addConstraint:constraint];
}
else {
    [self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[previousPlayerCardView]-[playerCardView(==previousPlayerCardView)]" options:0 metrics:nil views:@{@"previousPlayerCardView": player.previousPlayer.playerViewCard, @"playerCardView": player.playerViewCard}]];

    [self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[playerCardView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
}

if (self.constraintScrollViewRight) {
    [self.scrollViewMain removeConstraint:self.constraintScrollViewRight];
}

NSLayoutConstraint *constraintRight = [NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeRight multiplier:1 constant:10];
self.constraintScrollViewRight = constraintRight;
[self.scrollViewMain addConstraint:constraintRight];

[self.scrollViewMain layoutIfNeeded];
DLog(@"self.scrollViewMain: %@", self.scrollViewMain);
DLog(@"self.scrollViewMain.contentSize: %@", NSStringFromCGSize(self.scrollViewMain.contentSize));

The contentSize does become larger then the scroll view's frame:

2017-10-04 20:01:58.479446-0500 [ViewController addPlayer]_block_invoke [Line 242] self.scrollViewMain: <UIScrollView: 0x7fa9fd01b000; frame = (286 20; 462 1014); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x60000005ff20>; layer = <CALayer: 0x600000233580>; contentOffset: {0, 0}; contentSize: {826, 89}; adjustedContentInset: {0, 0, 0, 0}>
2017-10-04 20:01:58.479969-0500 [ViewController addPlayer]_block_invoke [Line 243] self.scrollViewMain.contentSize: {826, 89}

Why does iOS11 break my code?

EDIT:

Also, I try to scroll to the right to show the new subview when it appears:

    [self.scrollViewMain scrollRectToVisible:playerCardView.frame animated:YES];

And it does nothing.

SOLUTION:

I changed

[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[playerCardView(200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];

To

[self.scrollViewMain addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeLeft multiplier:1 constant:10]];

The UIScrollView now has a left and right anchor and can calculate its contentSize.

Kind of a crappy bug that the Visual Format is partially broken now.

like image 894
Padin215 Avatar asked Dec 19 '22 03:12

Padin215


2 Answers

Why does iOS11 break my code?

Because that is Apple's job.

like image 176
GeneCode Avatar answered Dec 24 '22 01:12

GeneCode


Try creating all your constraints without using NSLayoutConstraint constraintsWithVisualFormat:

I've just had the exact same problem in my app on iOS 11, after upgrading to XCode 9.

After several hours of trying to find out what constraint caused the problems in my code, I happened to replace all calls to NSLayoutConstraint constraintsWithVisualFormat: with building the constraints "by code" using NSLayoutConstraint constraintWithItem: instead; and now it works as it's supposed to...

I guess Apple has modified the visual format analyzer in a way that causes some unexpected side effects...

like image 24
Hypo Avatar answered Dec 24 '22 02:12

Hypo