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

时间:2022-11-22
本文介绍了关闭模式视图控制器后,框架不反映自动布局约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我使用的是 iOS 6、分页 UIScrollView 和纯自动布局.

I'm using iOS 6, a paging UIScrollView, and pure auto layout.

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

Summary: I created a view controller that scrolls pages of content. Some of the views are created and configured in storyboard, others programmatically. Here's the view hierarchy:

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

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

The constraints for the scroll view are configured in IB. Here's how I configured the constraints for the content view in code:

- (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 以模态方式呈现.视图控制器关闭后,系统似乎莫名其妙地修改了内容视图的框架,即使约束没有改变.

If the user taps an edit button, another view controller is presented modally using a segue in the storyboard. After the view controller is dismissed, the system appears to inexplicably modify the frame of the content view even though the constraints are unchanged.

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

I dismiss the presented view controller in the following delegate method:

- (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.解除视图控制器之前和之后的约束是相同的.

I don't understand how the x component of the frame's origin changed from 0 to -170. The constraints are identical before and after dismissing the view controller.

这是调用dismissViewControllerAnimated:completion:方法之前的框架和约束:

Here is the frame and the constraints right before calling the dismissViewControllerAnimated:completion: method:

(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 )>
)

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

Here is the frame and the constraints after the presenting view controller re-appears:

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 )>"
)

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

Why did the content view's frame change unexpectedly? And why doesn't it match what is dictated by the constraints?

对 hasAmbiguousLayout 的延迟调用令人惊讶地返回 false.不抛出异常.滚动视图甚至滚动,尽管内容视图部分在屏幕外.

A delayed call to hasAmbiguousLayout returns false surprisingly. No exceptions are thrown. The scroll view even scrolls, albeit the content view is partly off-screen.

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

No where do I explicitly set the scroll view's content size; I leave that to the system. The content view has an intrinsic size (the content view's size appears to be fine; it's the content view's origin that is the problem).

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

The scroll view's content offset is the same before and after dismissing the view controller. However, the displacement of the x component of the content view's origin is proportional to the content offset. The greater the content offset, the more negative the x component of the content view's origin is after the modal view controller is dismissed. And, at a content offset of "zero", the x component is zero. So if the modal view controller is presented while viewing the first page of content (when the content offset is "zero"), the content view's frame is correct upon dismissal of the view controller. The content-offset-of-zero case is the only circumstance in which the content view's frame correctly reflects its constraints.

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

I have tried inserting calls to layoutIfNeeded in various places with no results.

有什么建议吗?

推荐答案

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

I created a UIScrollView subclass that works around this issue (which BTW is fixed in 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

这篇关于关闭模式视图控制器后,框架不反映自动布局约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:禁用 UIPageViewController 弹跳 - Swift 下一篇:如何在 Swift 中设置 UIScrollView 高度

相关文章

最新文章