UISplitViewController 和复杂的视图层次结构

发布于 2024-08-29 02:16:12 字数 1016 浏览 4 评论 0原文

我正在做 iPad 技术演示,但遇到了严重的技术问题。

我有一个利用 UISplitViewController 的应用程序概念,但不作为整个应用程序的主控制器。

应用程序流程可以大致描述如下:

主屏幕(UIViewController) 列表->详细信息“目录”(UISplitViewController) 超级细节屏幕(UIViewController,但也可以想象是 SplitView 的子级)。

问题出在主页和目录之间的流程中。一旦 UISplitViewController 视图被添加到 UIWindow 中,它就会开始发出嘶嘶声。

问题可以概括为:

当 UISplitView 生成弹出视图时,它似乎被锁定到其父视图。从 UIWindow 子视图中删除 UISplitView 后,您将收到 CoreGraphics 异常,并且该视图将无法删除。

当添加其他视图(大概在本例中是您要返回的主屏幕)时,它们不会自动旋转,而是由于 CG 异常而未能删除的 UISplitView 继续响应旋转,导致可怕的渲染错误,无法仅“处理”。此时,添加任何视图,甚至重新添加 SplitView,都会导致一系列渲染错误。

然后,我尝试简单地将 SplitView 保留为“底部”视图,并不断在其顶部添加和删除主屏幕,但这失败了,因为 SplitView 主导了方向更改调用,并且主屏幕不会旋转,即使如果你调用 [homeScreen成为FirstResponder]

你不能将SplitView放入像UINavigationController这样的层次结构中,你将得到一个彻底的运行时错误,所以这个选项是不可能的。模态框看起来很糟糕,而且无论如何都是令人沮丧的。

我目前的假设是,处理这个问题的唯一正确方法是以某种方式“解除”UISplitViewController,以便可以将其从其父视图中删除而不会引发未处理的异常,但我不知道如何做。

如果您想查看一款完全满足我需要的应用程序,请查看 iPad 应用程序商店中的 GILT Groupe。他们成功了,但他们似乎已经编写了整个自定义视图转换集。

帮助将不胜感激。

I'm doing an iPad tech demo and I'm running into a serious technical problem.

I have an app concept that leverages UISplitViewController, but NOT as the primary controller for the entire app.

The app flow could be described roughly as this:

Home screen (UIViewController)
List->Detail "Catalog" (UISplitViewController)
Super Detail Screen (UIViewController but could conceivable also be a child of SplitView).

The problem is in the flow between Home and Catalog. Once a UISplitViewController view is added to the UIWindow, it starts to throw hissy fits.

The problem can be summarized at this:

When a UISplitView generates a popover view, it appears to then be latched to its parent view. Upon removing the UISplitView from the UIWindow subviews, you will get a CoreGraphics exception and the view will fail to be removed.

When adding other views (presumably in this case, the home screen to which you are returning), they do not autorotate, instead, the UISplitView, which has failed to be removed due to a CG exception, continues to respond to the rotation instead, causing horrible rendering bugs that can't be just "dealt with". At this point, adding any views, even re-adding the SplitView, causes a cascade of render bugs.

I then tried simply to leave the SplitView ever present as the "bottom" view, and keeping adding and removing the Home Screen from on top of it, but this fails as SplitView dominates the Orientation change calls, and Home Screen will not rotate, even if you call [homeScreen becomeFirstResponder]

You can't put SplitView into a hierarchy like UINavigationController, you will get an outright runtime error, so that option is off the table. Modals just look bad and are discourages anyway.

My presumption at this moment is that the only proper way to deal with this problem is so somehow "disarm" UISplitViewController so that it can be removed from its parent view without throwing an unhandled exception, but I have no idea how.

If you want to see an app that does exactly what I need to do, check out GILT Groupe in the iPad app store. They pulled it off, but they seem to have programmed an entire custom view transition set.

Help would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

我最亲爱的 2024-09-05 02:16:12

Apple 声明

分割视图控制器的视图
应始终以 root 身份安装
您的应用程序窗口的视图。你
永远不应该呈现分割视图
导航或标签栏内部
界面。

确实意味着它应该是根视图而不是另一个视图的子视图。尽管他们补充道:

您永远不应该在导航或标签栏界面内呈现分割视图

这并不意味着您可以将其添加为任何其他控制器的子视图。 (抱歉)

我有一种感觉,你所经历的一切是尝试这样做的副产品。事实上,令我惊讶的是 GILT Groupe 的应用程序没有被拒绝。 Apple 最近倾向于相当严格地执行这些 HIG 准则。当您尝试将它们添加到 NavigationController 时,它们(正如您已经发现的那样)会导致相当严重的运行时错误。

Apple states:

The split view controller’s view
should always be installed as the root
view of your application window. You
should never present a split view
inside of a navigation or tab bar
interface.

This does mean it should be root view and not subview of another view. Even though they add:

You should never present a split view inside of a navigation or tab bar interface

That does not mean you can add it as a subview of any other controller either. (sorry)

I have a feeling that what you are experiencing is the byproduct of trying to do so. I am actually surprised that GILT Groupe's app did not get rejected. Apple has a tendency to enforce these HIG guidelines rather strictly lately. They (as you found out already) cause a rather nasty runtime error when you attempt to add them to a NavigationController.

岁月苍老的讽刺 2024-09-05 02:16:12

我已经自己解决了这个问题...实际上解决了...通过将所有其他可能的全屏视图呈现为 SplitView 的模式...

这是我书中的一种令人讨厌的做事方式,但苹果让你别无选择如果您只想在应用程序中“有时”使用 SplitView。

I've solved this for myself... actually worked around... by presenting all other possible full screen views as modals of the SplitView...

This is an unsavory way of doing things in my book, but Apple leaves you little choice if you want to leverage a SplitView only "sometimes" within an app.

弥繁 2024-09-05 02:16:12

我通过创建第二个 UIWindow 取得了一些成功。我将 UISplitViewController 与其关联起来,并在我想显示 splitview 时将其与主窗口切换。它似乎按照我想要的方式工作,除了旋转方面的轻微延迟和有关“wait_fences”的日志消息。

I had some success by creating a second UIWindow. I associate the UISplitViewController with that, and switch it out with the main window when I want to show the splitview. It seems to work they way I wanted, except for a slight delay in rotations and a log message about "wait_fences".

苄①跕圉湢 2024-09-05 02:16:12

除非您为越狱设备进行开发,否则改变苹果的规则/愿望并不是一个好主意。就像 Jann 和 Jasconius 上面所说的那样,这意味着保留 splitView 控制器视图根,而不是过度使用模态(模糊)并且不使用多个窗口。

另外,Gilt 应用程序仅在美国

可用也试图找到解决方案,最终以编程方式从窗口中删除视图,就像 Tuannd 所说的那样,但景观渲染错误是不可原谅的。

@Jasconius,您在任何时候呈现的最大模态数量是多少?

Unless your developing for jail-broken devices then bending apples rules/wishes isn't a good idea. Like Jann and Jasconius state above this means keeping a splitView controller view root, not over-using modals (vague) and not using multiple windows.

Also, the Gilt app is only available in the US

I'v been trying to find a solution too and have ended up programatically removing views from the window like Tuannd talks about but the landscape rendering bug is unforgivable.

@Jasconius, What is the max number of modals are you are presenting at any time?

┼── 2024-09-05 02:16:12

我正在努力解决同样的问题。我一直在尝试将 UISplitViewController 作为黑匣子进行各种尝试,看看它的反应如何。

我似乎已经为我的案例提出了一个解决方案,并且效果令人满意。

关键似乎是添加到 UIWindow 的第一个视图是唯一正确初始化的视图。我遇到的所有问题往往都源于设备方向的错误通知。添加的第一个视图显然已正确配置。

就我而言,我不希望 UISplitView 作为第一个视图。以下内容对我有用。

应用程序委托 application:didFinishLaunching 方法很特殊。将视图添加到 UIWindow 必须在此处进行。如果在其他地方完成,则无法正确配置。

本质上,神奇之处在于将分割视图作为添加到窗口的第一个视图。只要保留 UISplitViewController 就可以删除它。从那时起,您可以交换其他视图,包括 UISplitView,并且大多数事情似乎都可以。

我仍然遇到了一些问题。分割视图以外的视图上的弹出窗口在视图框架和工具栏按钮的位置上会混淆,并且会显示在错误的位置。然后我将其放置在一个特定的位置,这似乎可以处理这种情况。

如果拆分视图上的弹出窗口仍然显示,并且您尝试查看另一个视图,则第二个视图的方向会混乱并显示为侧面。如果在显示弹出窗口之前访问该视图,则一切正常。我已经修复了这个问题,在切换到任何其他视图之前手动关闭弹出窗口。

如果有帮助的话,这是代码。所有的控制器都是appDelegate的实例变量

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // This also seems to work as good magic. Seems to set orientation and size properties that persist.
    [window addSubview:splitViewController.view];
    [splitViewController.view removeFromSuperview];

    [self switchToNewViewController:firstController];
    [window makeKeyAndVisible];
    return TRUE;
}

- (void)switchToNewViewController:(UIViewController *)newViewController {
    [popoverController dismissPopoverAnimated:FALSE];
    if (newViewController != currentViewController) {
        [currentViewController removeFromSuperview];
        currentViewController = newViewController;
        [window addSubView:newViewController.view];
     }
}

I am struggling with this same issue. I've been trying various things poking at the UISplitViewController as a black box and see how it reacts.

I seem to have come up with a solution to my case which seems to be working satisfactorily.

The key appears to be that the first view added to the UIWindow is the only view properly initialized. All the problems I've had tend to stem from incorrect notification of the orientation of the device. The first view added, apparently has this correctly configured.

In my case I didn't want the UISplitView as the first view. The following is working for me.

The app delegate application:didFinishLaunching method is special. Adding the view to the UIWindow must occur here. If it is done elsewhere it does not get configured properly.

Essentially the magic sauce, is have the split view be the first view added to the window. Its then ok to remove it as long as you retain the UISplitViewController. From then on you can swap other views in and out, including the UISplitView and most things seem to be ok.

I've still run into a few issues. Popovers on views other than the split view are confused on the views frames and location of toolbar buttons and will display in the wrong location. I place then in a specific location and that seems to handle that case.

If a popover on the split view is still displayed, and you try to view another view, the orientation of the second view is confused and shows up sideways. If that view is accessed before the popup is displayed, all is well. I've fixed this my manually dismissing the popover before switching to any other view.

Here's the code if it helps. All the controllers are instance variables of appDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // This also seems to work as good magic. Seems to set orientation and size properties that persist.
    [window addSubview:splitViewController.view];
    [splitViewController.view removeFromSuperview];

    [self switchToNewViewController:firstController];
    [window makeKeyAndVisible];
    return TRUE;
}

- (void)switchToNewViewController:(UIViewController *)newViewController {
    [popoverController dismissPopoverAnimated:FALSE];
    if (newViewController != currentViewController) {
        [currentViewController removeFromSuperview];
        currentViewController = newViewController;
        [window addSubView:newViewController.view];
     }
}
我三岁 2024-09-05 02:16:12

只是想说我遇到了同样的问题,找到了这个论坛主题,并遵循了上面 g051051 的建议。这对我来说非常有效。我没有看到任何故障,也没有在设备控制台中看到有关 wait_fences 的消息。

我只是使用 IB 在主 XIB 中创建两个 UIWindow 对象,正常创建 UISplitViewController,然后还创建一个从 UIViewController 派生的其他控制器的实例(我用于全屏显示)。我只是通过将每个 UIWindow 的 rootViewController 附加到其适当的控制器来将它们连接起来。

在 application:didLaunch...: 方法中,我可以决定向哪个窗口发送 makeKeyAndVisible 方法以及将哪个窗口设置为隐藏。当用户想要来回切换时,我只需将 makeKeyAndVisible 发送给其中一个,然后在另一个上设置隐藏属性,仅此而已。

如所示,所有与旋转相关的消息都会适当地发送到每个控制器,无论哪一个与当前可见窗口相关联。

无论如何,这对我来说非常有用,而且实际上很容易设置。

Just wanted to say that I was running into these same issues, found this forum topic, and followed the advice from g051051 above. This is working perfectly for me. I am not seeing any glitch, and no messages about wait_fences in the console of the device.

I simply used IB to create two UIWindow objects in the main XIB, created as normal the UISplitViewController and then also an instance of my other controller derived from UIViewController (which I am using for full screen display). I have simply hooked them up by attaching the rootViewController for each UIWindow to its appropriate controller.

In application:didLaunch...: method I can decide which window to send the makeKeyAndVisible method and which to set to hidden. When the user want to switch back and forth I simply have to send makeKeyAndVisible to one and set the hidden property on the other, that's all there is to it.

As indicated all of the rotation related messages are sent to each controller appropriately, regardless of which one is associated with the currently visible window.

Anyway, works great for me, and actually quite easy to set up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文