简体   繁体   English

Autolayout中的viewDidLayoutSubviews,在UIPageViewController上旋转

[英]viewDidLayoutSubviews in Autolayout with rotation on UIPageViewController

I have a UIPageViewController whose view controllers contain a UIScrollView which contains a UIImageView . 我有一个UIPageViewController其视图控制器包含一个UIScrollView ,其中包含一个UIImageView In the loaded view controller viewWillAppear , the bounds are incorrect if the view is rotated. 在加载的视图控制器viewWillAppear ,如果旋转视图,则边界不正确。 This is where I was trying to position the image view dynamically based on the size of the image according to this . 这就是我试图动态地基于根据所述图像的尺寸的图像视图定位 I tried to use (void)viewDidLayoutSubviews but I need to call [self.view layoutSubviews] or I get an assertion error. 我试图使用(void)viewDidLayoutSubviews但我需要调用[self.view layoutSubviews]或者我得到一个断言错误。 When I added that, then I can no longer zoom the image view. 当我添加它,然后我不能再缩放图像视图。 You can see it tries to zoom but get resized back to the minimum zoom. 您可以看到它尝试缩放但调整大小到最小缩放。

I am completely new to auto layout and was trying to see if I was missing something. 我对自动布局完全不熟悉,并试图看看我是否遗漏了一些东西。

My current fix involves checking the bounds of the frame to see if the orientation matches the bounds. 我目前的修复涉及检查框架的边界以查看方向是否与边界匹配。 If so then I use the bounds as is. 如果是这样,那么我按原样使用边界。 If not, then I switch the height and width in my calculations. 如果没有,那么我在计算中切换高度和宽度。

I'd like to know how to properly use viewDidLayoutSubviews without it taking away my ability to zoom in on the image view. 我想知道如何正确使用viewDidLayoutSubviews而不会剥夺我放大图像视图的能力。

From two of the answers, it looks like viewDidLayoutSubviews maybe the wrong place to layout the views. 从两个答案中,看起来viewDidLayoutSubviews可能是布局视图的错误位置。 I'm trying to find where this should be done and have the view's know their bounds and orientation but before they are visible on the screen. 我试图找到应该在哪里完成并让视图知道它们的边界和方向,但在它们在屏幕上可见之前。 From my reading, I thought that was viewDidLayoutSubviews but it seems using that could lead to an infinite loop. 从我的阅读,我认为这是viewDidLayoutSubviews但似乎使用可能会导致无限循环。

From two of the answers, it looks like viewDidLayoutSubviews maybe the wrong place to layout the views. 从两个答案中,看起来viewDidLayoutSubviews可能是布局视图的错误位置。 I'm trying to find where this should be done and have the view's know their bounds and orientation but before they are visible on the screen. 我试图找到应该在哪里完成并让视图知道它们的边界和方向,但在它们在屏幕上可见之前。

I would subclass UIScrollView and override there layoutSubviews , which will be called for you by the system only when needed and when all the variables (orientation, size, etc.) have the proper values. 我将子类化UIScrollView并覆盖layoutSubviews ,系统将仅在需要时以及所有变量(方向,大小等)具有适当的值时为您调用。

First, you shouldn't call -layoutSubviews yourself. 首先,你不应该自己调用-layoutSubviews From the UIView documentation for that method : 从该方法UIView 文档

You should not call this method directly. 您不应该直接调用此方法。 If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. 如果要强制进行布局更新,请在下次绘图更新之前调用setNeedsLayout方法。 If you want to update the layout of your views immediately, call the layoutIfNeeded method. 如果要立即更新视图的布局,请调用layoutIfNeeded方法。

Even without the warning, calling that method from -viewDidLayoutSubviews seems like a recipe for problems -- -viewDidLayoutSubviews is called to notify your view controller that its view just laid out it subviews, so calling [self.view layoutSubviews] might easily lead to a loop. 即使没有警告,从-viewDidLayoutSubviews调用该方法似乎也是问题的一个方法 - -viewDidLayoutSubviews来通知您的视图控制器它的视图只是将其设置为子视图,因此调用[self.view layoutSubviews]可能很容易导致环。

In the loaded view controller viewWillAppear, the bounds are incorrect if the view is rotated. 在加载的视图控制器viewWillAppear中,如果旋转视图,则边界不正确。

Remember that when -viewWillAppear is called, the view hasn't yet been added to a view hierarchy . 请记住,当-viewWillAppear时,视图尚未添加到视图层次结构中 Given that, it seems like your current approach isn't a bad one. 鉴于此,您的当前方法似乎并不坏。 The view doesn't yet have it's bounds set (because it hasn't been added yet), so you can determine what the bounds will be and use that to set up your view. 视图尚未设置其边界(因为它尚未添加),因此您可以确定边界的内容并使用它来设置视图。 Another, probably better approach would be to use -viewDidAppear , since your view will have been added at that point and should have the correct bounds by then. 另一个可能更好的方法是使用-viewDidAppear ,因为你的视图将在那时添加,并且应该具有正确的边界。

When I added that, then I can no longer zoom the image view. 当我添加它,然后我不能再缩放图像视图。 You can see it tries to zoom but get resized back to the minimum zoom. 您可以看到它尝试缩放但调整大小到最小缩放。

It sounds like you're not taking the zoomed state into account when you position your image view. 听起来您在放置图像视图时没有考虑缩放状态。 Make sure that your code in -viewDidLayoutSubviews isn't negating the work that the scroll view is doing. 确保-viewDidLayoutSubviews中的代码不会否定滚动视图正在执行的工作。

You shouldn't need to change the position of your image view at all -- that's exactly the kind of thing that auto layout is good at. 您根本不需要更改图像视图的位置 - 这正是自动布局擅长的那种。 I notice that the ImageScrollViewController.m file that you're using as an example doesn't change the location of the image view. 我注意到您作为示例使用的ImageScrollViewController.m文件不会更改图像视图的位置。

I'm not totally sure about your view hierarchy, but this answer explains how to do it if you have a view controller which view contains a UIScrollView. 我不完全确定您的视图层次结构,但是如果您有一个包含UIScrollView的视图控制器,则此答案将说明如何执行此操作。 (Said view controller is later shown in the UIPageViewController but that's irrelevant here). (所述视图控制器稍后在UIPageViewController中显示,但这与此无关)。

Override the following method in your view controller which controls the scroll view: 在视图控制器中覆盖以下控制滚动视图的方法:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

    CGRect bounds = self.view.bounds;
    self.scrollView.frame = bounds;

    //
    // Calculate a rect for your image view according to bounds
    //
    self.imageView.frame = calculatedFrame;
}

The problem is that your view will layout during scrolling/zooming, and if you position the view in viewDidLayoutSubviews of a view controller controlling a scrollView, you will position it every time the user scrolls or zooms. 问题是您的视图将在滚动/缩放期间进行布局,如果您将视图放置在控制scrollView的视图控制器的viewDidLayoutSubviews中,则每次用户滚动或缩放时都会对其进行定位。

I'm suspecting that your view controller might be controlling a UIScrollView directly, (instead of controlling a view that has a UIScrollView subview), and in that case, just remove the self.scrollView.frame = self.bounds row. 我怀疑你的视图控制器可能直接控制UIScrollView(而不是控制具有UIScrollView子视图的视图),在这种情况下,只需删除self.scrollView.frame = self.bounds行。

You should never call [self.view layoutSubviews] from viewDidLayoutSubviews. 你永远不应该从viewDidLayoutSubviews调用[self.view layoutSubviews]。 In fact, you should never call that function at all. 事实上,你根本不应该打电话给那个功能。 If you need to update your layout, you call [self.view setNeedsLayout]. 如果您需要更新布局,请调用[self.view setNeedsLayout]。 But when your view has performed its layoutSubviews, viewDidLayoutSubviews is automatically called. 但是当您的视图执行了其layoutSubviews时,会自动调用viewDidLayoutSubviews。 That means that if you call that function from there, you will get an infinite loop. 这意味着如果从那里调用该函数,您将获得无限循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM