使用 SwiftUI 在 WatchOS 中实现从主控制器导航到基于页面的控制器的问题

Posted

技术标签:

【中文标题】使用 SwiftUI 在 WatchOS 中实现从主控制器导航到基于页面的控制器的问题【英文标题】:Issues implementing navigation from a main controller to page based controllers in WatchOS using SwiftUI 【发布时间】:2019-10-24 17:39:55 【问题描述】:

我正在尝试使用 SwiftUI 做类似this 的事情。到目前为止,我能够从一个主视图转到基于页面的视图,但我无法在页面视图之间滚动。

故事板如下所示:

如您所见,我在情节提要中没有任何 seguesnext page relationships

我在 WKHostingControllerHC3(三者中的中间一个)的代码中实现这些。

HostingControllerHC3

class HC3: WKHostingController<CV> 

    override func awake(withContext context: Any?) 
        super.awake(withContext: context)
        WKInterfaceController.reloadRootPageControllers(withNames: ["HC2", "HC3", "HC4"], contexts: [context] , orientation: WKPageOrientation.horizontal, pageIndex: 1)
    
    override var body: CV 
        return CV()
    

问题是我无法在基于页面的视图之间导航。

其他 HostingController 有一个 WKHostingController 类型的类,如下所示:

class HC[#]: WKHostingController<CV> 
    override var body: CV 
        return CV()
    

它们在身份检查器中分配了类别,并且在属性检查器中也具有指定的 ID。

我使用 NavigationLink 从主控制器导航到基于分页的控制器这是视图或主主机控制器:

struct ContentView: View 
    var body: some View 
        NavigationLink(destinationName: "HC3")
            Text("Go to HC3")
        
    

例子:

尝试导航到基于页面的控制器中的其他页面时,我确实在控制台中遇到了一些错误

ComF: interfaceController for interfaceControllerID:13F0353 not found (clientIdentifier=(null))


SampleApp WatchKit Extension[319:69539] [default] -[SPRemoteInterface _interfaceControllerClientIDForControllerID:]:2358: ComF: clientIdentifier for interfaceControllerID:13F0353 not found. callStack:(
    0   WatchKit                            0x36dd72fc 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 172796
    1   WatchKit                            0x36dd90cc 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 180428
    2   WatchKit                            0x36dcf2cc spUtils_dispatchAsyncToMainThread + 40
    3   WatchKit                            0x36dd8db8 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 179640
    4   WatchKit                            0x36dcf2cc spUtils_dispatchAsyncToMainThread + 40
    5   WatchKit                            0x36dd6688 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 169608
    6   WatchKit                            0x36dd6564 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 169316
    7   WatchKit                            0x36dcd9f4 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 133620
    8   WatchKit                            0x36dd632c 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 168748
    9   WatchKit                            0x36dd623c 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 168508
    10  WatchKit                            0x36db0b74 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 15220
    11  WatchKit                            0x36dbae94 0045BA6A-0953-3B1D-915F-6ADB695CD163 + 56980
    12  UIKitCore                           0x4148aaf0 78873E50-5E9B-3AA3-A471-366668659CA2 + 9235184
    13  UIKitCore                           0x40d750ec 78873E50-5E9B-3AA3-A471-366668659CA2 + 1806572
    14  UIKitCore                           0x40d75454 78873E50-5E9B-3AA3-A471-366668659CA2 + 1807444
    15  UIKitCore                           0x40d74cf0 78873E50-5E9B-3AA3-A471-366668659CA2 + 1805552
    16  UIKitCore                           0x40d7934c 78873E50-5E9B-3AA3-A471-366668659CA2 + 1823564
    17  UIKitCore                           0x410af7f0 78873E50-5E9B-3AA3-A471-366668659CA2 + 5191664
    18  UIKitCore                           0x41185800 _UISceneSettingsDiffActionPerformChangesWithTransitionContext + 244

    .
    .
    .
    .

【问题讨论】:

【参考方案1】:

您的设计存在逻辑错误。 reloadRootPageController 函数应在顶部 WKHostingController 中调用,但应在“HC3”中调用。

 class HostingController: WKHostingController<ContentView> 

override func awake(withContext context: Any?) 
       super.awake(withContext: context)
       WKInterfaceController.reloadRootPageControllers(withNames: ["HC2", "HC3", "HC4"], contexts: [context] , orientation: WKPageOrientation.horizontal, pageIndex: 1)
   


override var body: ContentView 
    return ContentView()


如果在HC3中调用reloadRootPageControllers,那么奇怪的情况就是你遇到的。

否则,您必须在 HC3 设置中添加 conditional_once。

class HC3: WKHostingController<CV> 

 static var runOnce: Bool = true

 override func awake(withContext context: Any?) 
    super.awake(withContext: context)

    if HC3.runOnce  HC3.runOnce.toggle()
     WKInterfaceController.reloadRootPageControllers(withNames: ["HC2", "HC3", "HC4"], contexts: [context] , orientation: WKPageOrientation.horizontal, pageIndex: 1)
    

  

override var body: CV 
    return CV()

  

【讨论】:

我正在尝试执行以下操作:使用 NavigationLink 从 Main HostingController 导航到 HC3,然后在 HC2、HC3 和 HC4 之间进行基于页面的导航。如果我将reloadRootPageController 放在class HostingController: WKHostingController 中,那么我会直接转到基于页面的导航并跳过查看ContentView()。我正在尝试从本机锻炼应用程序复制导航。您在哪里选择一项工作,然后有 3 个页面可供导航(主页、设置页面和音乐页面等) 用户不会按下按钮并导航到 HC3 是顶部的 WKHostingController 吗?提前致谢! 我更新了答案。如果 loadingRootPage 在唤醒后只运行一次,您仍然可以使用 HC3。否则每次加载HC3时HC3都会一直加载RootPage。 @E.Coms 当我使用您的回答中建议的第一种方法时,HostingController 的 ContentView 将被忽略,用户会直接进入基于页面的导航。如果我从 HostingController 中删除 reloadRootPageControllers 调用,我会看到 ContentView,但在导航到页面视图时,我只看到我导航到的页面,而不是其他两个页面。 解决方案是使用静态 bool runOnce 从 HC3 调用 reloadRootPageControllers。有点脏,但效果很好。

以上是关于使用 SwiftUI 在 WatchOS 中实现从主控制器导航到基于页面的控制器的问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 SwiftUI 在 WatchOS 中适配 UI

为啥 EmptyView() 不能在带有 SwiftUI 的 WatchOS 上工作?

SwiftUI PresentationButton 在 watchOS 上单次使用后停止运行

如何从 WatchOS 的 SwiftUI 列表中删除分隔符?

在 SwiftUI 中隐藏 Picker 在 watchOS 上的焦点边界

如何在 node js 应用程序中实现从一个项目的 GCR 到另一个项目的 GCR 的容器图像复制?