关闭模态视图控制器后框架不反映自动布局约束

2023-11-22

我正在使用 iOS 6、分页 UIScrollView 和纯自动布局。

摘要:我创建了一个滚动内容页面的视图控制器。一些视图是在情节提要中创建和配置的,另一些则以编程方式创建和配置。这是视图层次结构:

- Main view (storyboard) 
  - UIScrollView (storyboard)
    - content view (programmatically)
      - subviews representing pages of content (programmatically)

滚动视图的约束在 IB 中配置。以下是我在代码中配置内容视图的约束的方法:

- (void)viewDidLoad
{
   // ABPageScrollerContentView is a subclass of UIView; it overrides intrinsicContentSize; the size is calculated without referencing the scroll view's dimensions
   self.contentView = [[ABPageScrollerContentView alloc] init];
   self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
   [self.pageScrollerView addSubview:self.contentView];

   // configure constraints between scroll view and content view...
   UIView *contentView = self.contentView;
   NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(contentView);

   [self.pageScrollerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewsDictionary]];
   [self.pageScrollerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewsDictionary]];

   // the content view's subviews are added/removed in the tilePages method (not shown); tilePages is called later in the view controller lifecycle...
}

如果用户点击编辑按钮,则会使用故事板中的 segue 以模态方式呈现另一个视图控制器。视图控制器被关闭后,即使约束没有改变,系统也会莫名其妙地修改内容视图的框架。

我在以下委托方法中关闭了呈现的视图控制器:

- (void)didExitEditPageViewVC:(id)controller
{
   // update currently displayed page view from data model...

   // logged content view frame = (0, 0; 1020, 460)

   [self dismissViewControllerAnimated:YES completion:^{

      // logged content view frame = (-170, 0; 1020, 460)
   }];
}

我不明白框架原点的 x 分量如何从 0 变为 -170。关闭视图控制器之前和之后的约束是相同的。

以下是调用missViewControllerAnimated:completion:方法之前的框架和约束:

(lldb) po self.contentView
$0 = 0x1ede2b40 <AEBPageScrollerContentView: 0x1ede2b40; frame = (0 0; 1020 460); layer = <CALayer: 0x1edd6f00>>

(lldb) po self.pageScrollerView.constraints
$1 = 0x1ed076c0 <__NSArrayM 0x1ed076c0>(
<NSLayoutConstraint:0x1ede2980 H:|-(0)-[AEBPageScrollerContentView:0x1ede2b40]   (Names: '|':UIScrollView:0x1edd3410 )>,
<NSLayoutConstraint:0x1eded480 H:[AEBPageScrollerContentView:0x1ede2b40]-(0)-|   (Names: '|':UIScrollView:0x1edd3410 )>,
<NSLayoutConstraint:0x1edecbc0 V:|-(0)-[AEBPageScrollerContentView:0x1ede2b40]   (Names: '|':UIScrollView:0x1edd3410 )>,
<NSLayoutConstraint:0x1ede1040 V:[AEBPageScrollerContentView:0x1ede2b40]-(0)-|   (Names: '|':UIScrollView:0x1edd3410 )>
)

这是呈现视图控制器重新出现后的框架和约束:

contentView = <AEBPageScrollerContentView: 0x1ede2b40; frame = (-170 0; 1020 460); layer = <CALayer: 0x1edd6f00>>

self.pageScrollerView.constraints =
(
    "<NSLayoutConstraint:0x1ede2980 H:|-(0)-[AEBPageScrollerContentView:0x1ede2b40]   (Names: '|':UIScrollView:0x1edd3410 )>",
    "<NSLayoutConstraint:0x1eded480 H:[AEBPageScrollerContentView:0x1ede2b40]-(0)-|   (Names: '|':UIScrollView:0x1edd3410 )>",
    "<NSLayoutConstraint:0x1edecbc0 V:|-(0)-[AEBPageScrollerContentView:0x1ede2b40]   (Names: '|':UIScrollView:0x1edd3410 )>",
    "<NSLayoutConstraint:0x1ede1040 V:[AEBPageScrollerContentView:0x1ede2b40]-(0)-|   (Names: '|':UIScrollView:0x1edd3410 )>"
)

为什么内容视图的框架发生意外变化?为什么它不符合约束条件?

对 hasAmbigouslyLayout 的延迟调用令人惊讶地返回 false。不会引发任何异常。滚动视图甚至可以滚动,尽管内容视图部分位于屏幕外。

我没有在哪里明确设置滚动视图的内容大小;我把它留给系统。内容视图具有固有的大小(内容视图的大小看起来没问题;问题在于内容视图的起源)。

滚动视图的内容偏移量在关闭视图控制器之前和之后是相同的。但是,内容视图原点的 x 分量的位移与内容偏移量成正比。内容偏移量越大,模态视图控制器关闭后内容视图原点的 x 分量的负值就越大。并且,在内容偏移量“零”时,x 分量为零。因此,如果在查看第一页内容时呈现模态视图控制器(当内容偏移量为“零”时),则在视图控制器解除后内容视图的框架是正确的。内容偏移量为零的情况是内容视图的框架正确反映其约束的唯一情况。

我尝试在不同的地方插入对layoutIfNeeded的调用,但没有结果。

有什么建议么?


我创建了一个 UIScrollView 子类来解决这个问题(顺便说一句,它在 iOS7 中已修复):

@interface ConstraintsSafeScrollView : UIScrollView
@end

@implementation ConstraintsSafeScrollView {
  CGPoint _savedContentOffset;
  UIEdgeInsets _savedContentInset;
}

- (void)willMoveToWindow:(UIWindow *)newWindow {
  if (newWindow) {
    // Reset the scrollview to the top.
    [super setContentOffset:CGPointMake(-_savedContentInset.left, -_savedContentInset.top)];
  }
  [super willMoveToWindow:newWindow];
}

// Overridden to store the latest value.
- (void)setContentOffset:(CGPoint)contentOffset {
  _savedContentOffset = contentOffset;
  [super setContentOffset:contentOffset];
}

// Overridden to store the latest value.
- (void)setContentInset:(UIEdgeInsets)contentInset {
  _savedContentInset = contentInset;
  [super setContentInset:contentInset];
}

- (void)didMoveToWindow {
  if (self.window) {
    // Restore offset and insets to their previous values.
    self.contentOffset = _savedContentOffset;
    self.contentInset = _savedContentInset;

  }
  [super didMoveToWindow];
}

@end
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关闭模态视图控制器后框架不反映自动布局约束 的相关文章

随机推荐