Essentials: [Enhancement] AppInfo.RequestedTheme is difficult to use in Xamarin Forms on iOS

Created on 26 Feb 2020  路  5Comments  路  Source: xamarin/Essentials

Description

Determining the current RequestedTheme using Xamarin Forms on iOS before the first Page is displayed does not appear to be possible.

My intended implementation is to have two different ResourceDictionaries, and choose which one to load based on the RequestedTheme. I would like to do this before displaying the first page, but I get a NullReferenceException on iOS because Platform.GetCurrentViewController() is null (no UIViewController has been created).

Would an implementation like the following work and be acceptable:

change

    return Platform.GetCurrentViewController().TraitCollection.UserInterfaceStyle switch
    {
        UIUserInterfaceStyle.Light => AppTheme.Light,
        UIUserInterfaceStyle.Dark => AppTheme.Dark,
        _ => AppTheme.Unspecified
    };

to

    var viewController = Platform.GetCurrentViewController() ?? new UIViewController();
    return viewController.TraitCollection.UserInterfaceStyle switch
    {
        UIUserInterfaceStyle.Light => AppTheme.Light,
        UIUserInterfaceStyle.Dark => AppTheme.Dark,
        _ => AppTheme.Unspecified
    };

I don't actually know if a newly created UIViewController works for this.

bug

All 5 comments

I think we can check the current UIWindow perhaps instead of the Controller.

After looking at this:

https://developer.apple.com/documentation/uikit/uitraitcollection/3238080-current

It's also possible UITraitCollection.Current.UserInterfaceStyle might work, avoiding the view controller completely.

Yeah, so basically we can try to get the controller, but if null then use that! Love it!

I am still getting an error with this using Xamarin.Essentials 1.5.2 in iPhone 11 simulator running iOS 13.4.1

System.NullReferenceException: Object reference not set to an instance of an object
  at Xamarin.Essentials.Platform.GetCurrentViewController (System.Boolean throwIfNull) [0x0000d] in d:\a\1\s\Xamarin.Essentials\Platform\Platform.ios.tvos.watchos.cs:69 
  at Xamarin.Essentials.Platform.GetCurrentUIViewController () [0x00000] in d:\a\1\s\Xamarin.Essentials\Platform\Platform.ios.tvos.watchos.cs:61 
  at Xamarin.Essentials.AppInfo.PlatformRequestedTheme () [0x0000c] in d:\a\1\s\Xamarin.Essentials\AppInfo\AppInfo.ios.tvos.watchos.cs:33 
  at Xamarin.Essentials.AppInfo.get_RequestedTheme () [0x00000] in d:\a\1\s\Xamarin.Essentials\AppInfo\AppInfo.shared.cs:19 
  at xxx-appname-xxx.AppDelegate.FinishedLaunching (UIKit.UIApplication app, Foundation.NSDictionary options) [0x000cc] in /Users/joe/Projects/xxx-appname-xxx/AppDelegate.cs:93 
  at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.16.0.13/src/Xamarin.iOS/UIKit/UIApplication.cs:86 
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0000e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.16.0.13/src/Xamarin.iOS/UIKit/UIApplication.cs:65 
  at xxx-appname-xxx.Application.Main (System.String[] args) [0x00052] in /Users/joe/Projects/xxx-appname-xxx/Main.cs:34 ____________________________________________________________

This is in a classic iOS project that uses Forms embedding. I tried it both before and after Xamarin.Forms.Forms.Init() and I got the same result. However, I would expect to work in classic iOS without the Init as the documentation doesn't say the Forms is a prerequisite: https://docs.microsoft.com/en-au/xamarin/essentials/app-theme?context=xamarin%2Fxamarin-forms&tabs=uwp

It looks like a bug in the implementation:

var uiStyle = Platform.GetCurrentUIViewController()?.TraitCollection?.UserInterfaceStyle ?? UITraitCollection.CurrentTraitCollection.UserInterfaceStyle;

needs to be

var uiStyle = Platform.GetCurrentUIViewController(false)?.TraitCollection?.UserInterfaceStyle ?? UITraitCollection.CurrentTraitCollection.UserInterfaceStyle;

to avoid throwing.

Was this page helpful?
0 / 5 - 0 ratings