当应用程序从后台返回时,Xamarin iOS 呈现不同的视图控制器

Posted

技术标签:

【中文标题】当应用程序从后台返回时,Xamarin iOS 呈现不同的视图控制器【英文标题】:Xamarin iOS present a different view controller when app returns from background 【发布时间】:2019-06-13 13:10:12 【问题描述】:

我正在开发的 xamarin ios 应用程序需要始终启用 GPS。首次安装应用程序时,用户会收到启用 GPS 的提示,但用户可以选择在设备级别关闭定位服务。

我希望我的应用程序提示(即 NAG)用户启用 gps。因此,我创建了一个新的视图控制器和相应的 xib 文件。 xib文件长这样

我在 WillEnterForeground 中添加了以下代码并且没有错误,但是显示了视图,但是如果启用了 gps,则显示的不是以前的活动视图。

     public override void WillEnterForeground(UIApplication application)
            
                Console.WriteLine("App will enter foreground");
                if (CLLocationManager.Status == CLAuthorizationStatus.Denied 
                    || CLLocationManager.Status == CLAuthorizationStatus.Restricted
                    || CLLocationManager.Status == CLAuthorizationStatus.NotDetermined)
                

                    window = new UIWindow(UIScreen.MainScreen.Bounds);

                    var rootNavigationController = new UINavigationController();
                    rootNavigationController.PushViewController(new LocationServicesVerifyViewController(), false);
window.RootViewController = rootNavigationController;
                    window.MakeKeyAndVisible();

                
            

我的想法是在应用程序启动时或在未启用定位服务时从后台返回时呈现此视图。

单击启用 GPS 按钮将运行以下代码,基本上会将用户带到设备上的位置部分。

            if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
            
                NSString settingsString = UIApplication.OpenSettingsUrlString;
                NSUrl url = new NSUrl(settingsString);
                UIApplication.SharedApplication.OpenUrl(url);
            

我的班级声明是

  // class-level declarations
        UIWindow window;

我目前完成的启动方式是这样的

public override bool FinishedLaunching(UIApplication app, NSDictionary options)

    AppDelegate.Self = this;

    window = new UIWindow(UIScreen.MainScreen.Bounds);

    var rootNavigationController = new UINavigationController();
    window.RootViewController = rootNavigationController;

    DataAccess.CheckDatabase();

    if (DataAccess.GetLicence().APIKey == "")
    
        rootNavigationController.PushViewController(new LicenceActivationViewController(), false);
    
    else
    
        rootNavigationController.PushViewController(new JobListViewController(), false);
    

    window.MakeKeyAndVisible();

    return true;


【问题讨论】:

【参考方案1】:

首先,当您想在 AppDelegate 中显示LocationServicesVerifyViewController 时,无需创建新窗口。您可以使用:Window.RootViewController 获取当前窗口的根视图控制器。然后在该视图控制器上方显示一个新控制器。

其次,当位置状态被拒绝时,我们应该检测当前顶部呈现的视图控制器的类型。如果已经是LocationServicesVerifyViewController,就不要再出现了。

最后,当用户更改位置状态并返回应用程序时。我们可以通过关闭当前顶部呈现的视图控制器来显示上一个视图控制器。

这是我的代码供您参考:

public override void WillEnterForeground(UIApplication application)


    if (CLLocationManager.Status == CLAuthorizationStatus.Denied
            || CLLocationManager.Status == CLAuthorizationStatus.Restricted
            || CLLocationManager.Status == CLAuthorizationStatus.NotDetermined)
    
        var topViewController = GetTopPresented(Window.RootViewController);

        if ( !(topViewController is LocationServicesVerifyViewController))
        
            LocationServicesVerifyViewController controller = (LocationServicesVerifyViewController)UIStoryboard.FromName("Main", null).InstantiateViewController("LocationServicesVerifyViewController");
            topViewController.PresentViewController(controller, true, null);
                        
    
    else
    
        var topViewController = GetTopPresented(Window.RootViewController);

        if (topViewController is LocationServicesVerifyViewController)
        
            topViewController.DismissViewController(true, null);
        
    


UIViewController GetTopPresented(UIViewController viewController)

    if (viewController.PresentedViewController != null)
    
        return GetTopPresented(viewController.PresentedViewController);
    
    else
    
        return viewController;
    

我在 Main.storyboard 中定义了LocationServicesVerifyViewController,所以它的构造函数是不同的。但是不影响其他的,这部分可以随意修改。

【讨论】:

当我使用此代码时,我在分配 topViewController 'Foundation.ModelNotImplementedException' 时遇到异常。看起来窗口没有实现,我可能必须在这里创建一个窗口。有什么想法吗? @Abe 你还没有在 FinishedLaunching 事件中初始化 Window? 我已经在完成启动时初始化了窗口,请查看我更新的问题。抱歉,我对此很陌生,希望我正确回答了您的问题。 @Abe 我注意到你定义了一个新的UIWindow 称为窗口。但是UIApplicationDelegate 已经有一个名为Window 的属性。也许您只初始化了自己的属性。所以请注意windowWindow之间的大小写。我认为 window 在您的情况下是有效的。 嗨,就是这样,将 Window 更改为 window 并取得了一些进展。但是我得到了错误。 Foundation.MonoTouchException:抛出 Objective-C 异常。名称:NSInvalidArgumentException 原因:在捆绑包 NSBundle /containers/Bundle/Application/1C3364EE-1115-434A-AB97-C8A6A0C0E8CB/JourneaseMobile_iOS.app> 中找不到名为“Main”的情节提要我没有使用情节提要,而是使用 xib 文件以及您的示例中的“主要”。在呈现新视图之前我想要的视图?

以上是关于当应用程序从后台返回时,Xamarin iOS 呈现不同的视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin Forms iOS 在唤醒时冻结

Xamarin Forms - 每 10 秒获取一次设备位置(当应用程序在前台/后台运行时)

从后台返回时iOS应用程序请求失败

当应用程序从后台返回时如何隐藏飞溅?

当 Xamarin.ios Uitest 从 Xamarin Studio 运行时,在 Xamarin 测试云上面临“停滞的错误”

iOS - UIToolbar 从后台返回后调整大小