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.
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.