【问题标题】:Positioning UIViewControllers in UIScrollView side by side在 UIScrollView 中并排定位 UIViewControllers
【发布时间】:2012-08-19 16:19:21
【问题描述】:

我有一个主视图控制器,它有一个 UIScrollView 的子视图和另外 2 个 UIViewControllers(每个都有 nibs UIView 和按钮)。使用 addSubView 方法将 UIViewControllers 的 UIView 添加到 UIScrollView 中。而且我想将两个 UIViewController 并排放置。

我有以下代码,但它似乎不起作用。

[self scrollView].pagingEnabled = YES;
[self scrollView].contentSize = CGSizeMake(768 * 2, 1024);
[[self scrollView] setDelegate:self];

CGRect frame1;
frame1.origin.x = 0;
frame1.origin.y = 0;
frame1.size = CGSizeMake(768, 1024);

// Model one
oneView = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil];
//oneView.view.frame = frame1;
[self.scrollView addSubview:oneView.view];
oneView.view.frame = frame1;

// Model two

CGRect frame2;
frame2.origin.x = 768;
frame2.origin.y = 0;
frame2.size = CGSizeMake(768, 1024);

twoView = [[TwoViewController alloc] initWithNibName:@"TwoViewController" bundle:nil];
//twoView.view.frame = frame2;
[self.scrollView addSubview:twoView.view];
twoView.view.frame = frame2;

为什么我设置了frame.origin.x后,UIScrollView里面的oneView和twoView在同一个地方? twoView 似乎在 oneView 的顶部,它应该并排放置?知道我在哪里做错了吗?谢谢!

更新:这是我在 github 上的完整项目代码:http://bit.ly/PLe1Le

【问题讨论】:

  • 只说frame.origin.x = 768;会有什么问题
  • 我正在测试超过 2 个 UIViewControllers 作为 UIScrollView 的子视图,当代码不起作用时,我决定缩小范围并将 x 保留原样。我会将上面的代码更改为您指定的代码,以便更清晰。
  • 仅供参考,您没有将 Xcode 项目文件签入存储库。
  • 糟糕,更新了存储库。它现在有 Xcode 项目文件。
  • 谢谢。我认为,发生的事情类似于下面 torrey.lyons 的回答。如果内容视图的高度达到或超过 1024 像素,它就会发生,如果你不让它们变得那么高,它就不会。我不知道为什么 - 它实际上与内容大小上的任何内容都没有关联。虽然我还不能回答你为什么会发生这种情况,但如果你认为这足以支付赏金,我可以给你一个解决问题的代码的答案。

标签: ios xcode uiviewcontroller uiscrollview


【解决方案1】:

从这篇文章中借用一些代码:UIScrollView adding UIViewController as a sub view? with UIPageControl,我想我通过使用 self.scrollView.frame.size.width 而不是使用固定值 768 来修复它。

[self scrollView].pagingEnabled = YES;
[self scrollView].contentSize = CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height);
[[self scrollView] setDelegate:self];

CGRect frame1;
frame1.origin.x = self.scrollView.frame.size.width * 0;
frame1.origin.y = 0;
frame1.size = self.scrollView.frame.size;

// Model one
oneView = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil];
[self.scrollView addSubview:oneView.view];
oneView.view.frame = frame1;

// Model two
CGRect frame2;
frame2.origin.x = self.scrollView.frame.size.width * 1;
frame2.origin.y = 0;
frame2.size = self.scrollView.frame.size;

twoView = [[TwoViewController alloc] initWithNibName:@"TwoViewController" bundle:nil];
[self.scrollView addSubview:twoView.view];
twoView.view.frame = frame2;

另外,我已经更新了我的存储库,以便您可以对整个项目进行测试。这是链接:http://bit.ly/PLe1Le :)

【讨论】:

    【解决方案2】:

    这种情况开始发生的原因是,作为UIViewControllerview 属性值的任何UIView 实例有时会收到一条消息,将其视图调整为其超级视图的视图。

    具体来说,当视图控制器的 view 添加到窗口时,将调用未记录的方法 viewDidMoveToWindow:shouldAppearOrDisappear:,就像在本例中启动应用程序时发生的那样。此时,如果视图控制器的view实例是主窗口的大小或更大,它将被调整为其父视图的大小。

    原始代码采用从 .xib 加载的两个视图并将它们的大小调整为 768 * 1024,即窗口大小。这发生在 之前 -makeKeyAndVisible 在窗口上被调用,最终触发调整大小。我在应用程序委托中使用 KVO 来观察框架的大小调整;这是调整大小时的堆栈跟踪:

    * thread #1: tid = 0x1f03, 0x000030f9 scroller`-[ViewController observeValueForKeyPath:ofObject:change:context:] + 105 at ViewController.m:71, stop reason = breakpoint 1.1
        frame #0: 0x000030f9 scroller`-[ViewController observeValueForKeyPath:ofObject:change:context:] + 105 at ViewController.m:71
        frame #1: 0x0093ad91 Foundation`NSKeyValueNotifyObserver + 345
        frame #2: 0x0093a895 Foundation`NSKeyValueDidChange + 438
        frame #3: 0x0092033e Foundation`-[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 131
        frame #4: 0x009cdcb4 Foundation`_NSSetRectValueAndNotify + 187
        frame #5: 0x000e1786 UIKit`-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:] + 657
        frame #6: 0x0005310c UIKit`-[UIView(Internal) _didMoveFromWindow:toWindow:] + 1040
        frame #7: 0x00052edb UIKit`-[UIView(Internal) _didMoveFromWindow:toWindow:] + 479
        frame #8: 0x0005d5ab UIKit`-[UIScrollView _didMoveFromWindow:toWindow:] + 65
        frame #9: 0x00052edb UIKit`-[UIView(Internal) _didMoveFromWindow:toWindow:] + 479
        frame #10: 0x0004f692 UIKit`-[UIView(Hierarchy) _postMovedFromSuperview:] + 158
        frame #11: 0x0005446f UIKit`-[UIView(Internal) _addSubview:positioned:relativeTo:] + 1633
        frame #12: 0x0004e14b UIKit`-[UIView(Hierarchy) addSubview:] + 56
        frame #13: 0x0003d550 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 380
        frame #14: 0x0003d670 UIKit`-[UIWindow _setHidden:forced:] + 280
        frame #15: 0x0003d836 UIKit`-[UIWindow _orderFrontWithoutMakingKey] + 49
        frame #16: 0x0004472a UIKit`-[UIWindow makeKeyAndVisible] + 35
        frame #17: 0x00002575 scroller`-[AppDelegate application:didFinishLaunchingWithOptions:] + 661 at AppDelegate.m:21
        frame #18: 0x00015386 UIKit`-[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1292
        frame #19: 0x00016274 UIKit`-[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 524
        frame #20: 0x00025183 UIKit`-[UIApplication handleEvent:withNewEvent:] + 1027
        frame #21: 0x00025c38 UIKit`-[UIApplication sendEvent:] + 68
        frame #22: 0x00019634 UIKit`_UIApplicationHandleEvent + 8196
        frame #23: 0x0139eef5 GraphicsServices`PurpleEventCallback + 1274
        frame #24: 0x01488195 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
        frame #25: 0x013ecff2 CoreFoundation`__CFRunLoopDoSource1 + 146
        frame #26: 0x013eb8da CoreFoundation`__CFRunLoopRun + 2218
        frame #27: 0x013ead84 CoreFoundation`CFRunLoopRunSpecific + 212
        frame #28: 0x013eac9b CoreFoundation`CFRunLoopRunInMode + 123
        frame #29: 0x00015c65 UIKit`-[UIApplication _run] + 576
        frame #30: 0x00017626 UIKit`UIApplicationMain + 1163
        frame #31: 0x000022ad scroller`main + 141 at main.m:16
    

    我们可以通过实例化视图并同时将其添加到滚动视图来验证是否发生这种情况,因为内容视图是UIViewController 的视图实例。我在ViewControllerviewDidLoad 实现的末尾添加了以下代码:

    CGRect frame3 = frame2;
    frame3.origin.x = 768.0f * 2.0f;
    UIView *thirdView = [[UIView alloc] initWithFrame:frame3];
    [thirdView setBackgroundColor:[UIColor redColor]];
    [self.scrollView addSubview:thirdView];
    

    以及将分配内容大小的行更改为:

    [self scrollView].contentSize = CGSizeMake(768 * 3, 1024);
    

    此视图在makeKeyAndVisible 期间未设置其框架,并且位于正确的位置。

    要解决此问题,我建议在窗口调用 -makeKeyAndVisible 之后设置视图层次结构,可能在 viewWillAppear 中(不确定是否会出现相同的问题)或以其他方式构建代码以延迟滚动视图的布局。或者,稍后重新设置框架以明确撤消此错误。

    我希望这有助于解释正在发生的事情,并且我提供的证据清晰可信;看来您已经针对您的特定情况进行了修复,但希望当UIViewController 将其视图布置在滚动视图中时,此答案可以作为框架不当行为的通用解决方案。

    【讨论】:

    • 感谢卡尔的解释!赏金将在 1 小时内发放(系统限制)。 :)
    • 非常感谢 Eddy,我真的很感激。让我知道我是否可以以任何其他方式帮助您或进一步澄清这一点。谢谢!
    【解决方案3】:

    我怀疑您的问题是您的两个视图垂直太大而无法适应滚动视图的内容大小。您的滚动视图的内容仅为 (768 * 2) x 900。您将两个子视图的大小调整为 768 x 1024。由于它们无论如何都不适合,滚动视图可能只是给我们并将它们都放在原点。将您的第二行更改为:

    [self scrollView].contentSize = CGSizeMake(768 * 2, 1024);
    

    【讨论】:

    • 我将 UIViewController 的 height 编辑为 900,以查看是否可以从模拟器中看到重叠或其他内容。但是找不到任何东西,所以我将其恢复为 1024。我已经更新了上面的代码,并在我的源代码中添加了一个 github 链接。
    【解决方案4】:

    您是否尝试过先将子视图添加到滚动视图,然后设置它们的位置?我发现在另一种情况下,我试图在滚动视图中显示之前向视图添加信息,只是为了让文本字段为空白。视图有一个奇怪的怪癖,即在显示时值可能会返回到它们的默认值。

    【讨论】:

    • 我尝试在将 UIViewControllers 添加到 UIScrollView 之前和之后设置它们的位置。请通过 github 链接查看我上面的更新。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多