iOS AutoLayout issue with ScrollView

2020-04-14 03:10发布

问题:

Hello i have an auto layout issue with UIScrollView and ModalViewController. Here are my coding steps as sample code:

1) I have an UIViewController with an UIScrollView as subView

UIViewController *viewController = [[UIViewController alloc] init];
UIScrollView *scrollView = [[UIScrollView alloc] init];

scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[viewController.view addSubview:scrollView];

UIView *superView = viewController.view;
NSDictionary *viewsDict = NSDictionaryOfVariableBindings(superView,scrollView);

[superView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView(==superView)]|"
                                                                  options:0
                                                                  metrics:nil
                                                                    views:viewsDict]];
[superView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView(==superView)]|"
                                                                  options:0
                                                                  metrics:nil
                                                                    views:viewsDict]];

this works

2) i add 2 sub views to the scrollView

UIView *view1 = [[UIView alloc] init];
view1.backgroundColor = [UIColor redColor];
view1.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:view1];


UIView *view2 = [[UIView alloc] init];
view2.backgroundColor = [UIColor greenColor];
view2.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:view2];

viewsDict = NSDictionaryOfVariableBindings(scrollView,view1,view2);


[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view1(==scrollView)]|"
                                                                   options:0
                                                                   metrics:nil
                                                                     views:viewsDict]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view2(==scrollView)]|"
                                                                   options:0
                                                                   metrics:nil
                                                                     views:viewsDict]];

[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view1(180)][view2(==scrollView)]|"
                                                                   options:0
                                                                   metrics:nil
                                                                     views:viewsDict]];


UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setTitle:@"open" forState:UIControlStateNormal];
btn.frame = CGRectMake(10, 10, 100, 100);
[view2 addSubview:btn];
[btn addTarget:self action:@selector(openPopOver) forControlEvents:UIControlEventTouchUpInside];

this works also fine

3) I scroll to content offset y 180 that i can only see the view2

[scrollView setContentOffset:CGPointMake(0, 180) animated:YES];

4) I open a ModalViewController on the `ViewController

- (void)openModal{
UIViewController *viewController = [[UIViewController alloc] init];

UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setTitle:@"close" forState:UIControlStateNormal];
btn.frame = CGRectMake(10, 10, 100, 100);
[viewController.view addSubview:btn];
[btn addTarget:self action:@selector(closePopOver) forControlEvents:UIControlEventTouchUpInside];


[self presentViewController:viewController animated:YES completion:nil];

}

5) when i close the ModalViewController my Layout on the scrollView didn't work it scrolls to an different content offset that i have not set. When i reset the content offset to y 180 the content size of the scrollview is wrong.

- (void)closeModal{
[self dismissViewControllerAnimated:YES completion:^{

}];

}

I hope someone can help me to fix this problem.

回答1:

From the documentation of UIViewController's presentViewController: method:

This method sets the presentedViewController property to the specified view controller, resizes that view controller’s view and then adds the view to the view hierarchy. The view is animated onscreen according to the transition style specified in the modalTransitionStyle property of the presented view controller.

So the resizing of your view controller is intended. Well, by Apple, anyway.

One way to go about this is to log the resized view's coordinates and infer what exactly has been changed. Maybe you can adjust your constraints in a way to prevent this.

Alternatively, you could try resizing everything in the completion handler of this method.



回答2:

I think this might be a bug in iOS autolayout wrt UIScrollViews. I was having a similar problem only in my case, I would push to a detail view, then pop back to the master view which is a UIScrollView. Content in the scroll view would be shifted up. Scrolling the scroll view to the top, then pushing and popping again and things would be properly reset.

I even tried plain out of the box master detail app using a UIScrollView instead of a table view as master, and was able to demonstrate the defect.

Table views and Collection views do not seem to have this problem.



回答3:

Perhaps you can reset the contentoffset in the viewWillAppear? And did you already implement -(void)layoutsubviews?