【问题标题】:How to Check For Dark Mode in Xamarin.Forms如何在 Xamarin.Forms 中检查暗模式
【发布时间】:2020-01-12 17:26:15
【问题描述】:

现在 iOS 13Android Q 允许用户在操作系统级别启用暗模式,我如何在 Xamarin.Forms 中检查它?

我在我的 Xamarin.Forms 项目中创建了这个,但我不确定如何从 Xamarin.iOS 和 Xamarin.Android 中检索值。

IEnvironment.cs

using System.Threading.Tasks;

namespace MyNamespace
{
    public interface IEnvironment
    {
        Theme GetOperatingSystemTheme();
        Task<Theme> GetOperatingSystemThemeAsync();
    }

    public enum Theme { Light, Dark }
}

App.cs

using Xamarin.Forms;

namespace MyNamespace
{
    public App : Application
    {
        // ...

        protected override async void OnStart()
        {
            base.OnStart();

            Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();

            SetTheme(theme);
        }

        protected override async void OnResume()
        {
            base.OnResume();

            Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();

            SetTheme(theme);
        }

        void SetTheme(Theme theme)
        {
            //Handle Light Theme & Dark Theme
        }
    }
}

【问题讨论】:

    标签: xamarin.forms xamarin.android xamarin.ios


    【解决方案1】:

    截至 2020 年 4 月的更新:

    不再需要使用特定于平台的服务来检查 Xamarin.Forms 中的亮/暗模式。

    我们现在可以通过以下方式直接获取当前主题:

    OSAppTheme currentTheme = Application.Current.RequestedTheme;
    

    其中RequestedTheme 属性返回OSAppTheme 枚举成员:UnspecifiedDarkLight

    有关详细信息:请参阅documentationupdated Xamarin.Forms Application.cs code

    【讨论】:

    【解决方案2】:

    我们可以使用 Xamarin.Forms 依赖服务从 iOS 和 Android 访问特定于平台的代码。

    我在这篇博文中进行了更深入的介绍: https://codetraveler.io/2019/09/10/check-for-dark-mode-in-xamarin-forms/

    Xamarin.Forms 代码

    环境

    using System.Threading.Tasks;
    
    namespace MyNamespace
    {
        public interface IEnvironment
        {
            Theme GetOperatingSystemTheme();
            Task<Theme> GetOperatingSystemThemeAsync();
        }
    
        public enum Theme { Light, Dark }
    }
    

    App.cs

    using Xamarin.Forms;
    
    namespace MyNamespace
    {
        public App : Application
        {
            // ...
    
            protected override async void OnStart()
            {
                base.OnStart();
    
                Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
    
                SetTheme(theme);
            }
    
            protected override async void OnResume()
            {
                base.OnResume();
    
                Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
    
                SetTheme(theme);
            }
    
            void SetTheme(Theme theme)
            {
                //Handle Light Theme & Dark Theme
            }
        }
    }
    

    Xamarin.iOS

    using System;
    using UIKit;
    using Xamarin.Forms;
    using MyNamespace;
    using MyNamespace.iOS;
    
    [assembly: Dependency(typeof(Environment_iOS))]
    namespace MyNamespace.iOS
    {
        public class Environment_iOS : IEnvironment
        { 
            public Theme GetOperatingSystemTheme()
            {
                //Ensure the current device is running 12.0 or higher, because `TraitCollection.UserInterfaceStyle` was introduced in iOS 12.0
                if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
                {
                    var currentUIViewController = GetVisibleViewController();
    
                    var userInterfaceStyle = currentUIViewController.TraitCollection.UserInterfaceStyle;
    
                    switch (userInterfaceStyle)
                    {
                        case UIUserInterfaceStyle.Light:
                            return Theme.Light;
                        case UIUserInterfaceStyle.Dark:
                            return Theme.Dark;
                        default:
                            throw new NotSupportedException($"UIUserInterfaceStyle {userInterfaceStyle} not supported");
                    }
                }
                else
                {
                    return Theme.Light;
                }
            }
    
            // UIApplication.SharedApplication can only be referenced by the Main Thread, so we'll use Device.InvokeOnMainThreadAsync which was introduced in Xamarin.Forms v4.2.0
            public async Task<Theme> GetOperatingSystemThemeAsync() =>
                Device.InvokeOnMainThreadAsync(GetOperatingSystemTheme);
    
            static UIViewController GetVisibleViewController()
            {
                UIViewController viewController = null;
    
                var window = UIApplication.SharedApplication.KeyWindow;
    
                if (window.WindowLevel == UIWindowLevel.Normal)
                    viewController = window.RootViewController;
    
                if (viewController is null)
                {
                    window = UIApplication.SharedApplication
                        .Windows
                        .OrderByDescending(w => w.WindowLevel)
                        .FirstOrDefault(w => w.RootViewController != null && w.WindowLevel == UIWindowLevel.Normal);
    
                    if (window is null)
                        throw new InvalidOperationException("Could not find current view controller.");
    
                    viewController = window.RootViewController;
                }
    
                while (viewController.PresentedViewController != null)
                    viewController = viewController.PresentedViewController;
    
                return viewController;
            }
        }
    }
    

    Xamarin.Android

    using System;
    using System.Threading.Tasks;
    using Android.Content.Res;
    using Plugin.CurrentActivity;
    using Xamarin.Forms;
    
    using MyNamespace;
    using MyNamespace.Android;
    
    [assembly: Dependency(typeof(Environment_Android))]
    namespace MyNamespace.Android
    {
        public class Environment_Android : IEnvironment
        {
            public Task<Theme> GetOperatingSystemThemeAsync()  =>
                Task.FromResult(GetOperatingSystemTheme());
    
            public Theme GetOperatingSystemTheme()
            {
                //Ensure the device is running Android Froyo or higher because UIMode was added in Android Froyo, API 8.0
                if(Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
                {
                    var uiModeFlags = CrossCurrentActivity.Current.AppContext.Resources.Configuration.UiMode & UiMode.NightMask;
    
                    switch(uiModelFlags)
                    {
                        case UiMode.NightYes:
                            return Theme.Dark;
    
                        case UiMode.NightNo:
                            return Theme.Light;
    
                        default:
                            throw new NotSupportedException($"UiMode {uiModelFlags} not supported");
                    }
                }
                else
                {
                    return Theme.Light;
                }
            }
        }
    }
    

    【讨论】:

    • 别忘了采纳你的答案,这将帮助更多的人:)
    • 不使用 CrossCurrentActivity 可以做到吗?
    • @stephan14x 是 - Plugin.CurrentActivity 是开源的,您可以参考它的实现:github.com/jamesmontemagno/CurrentActivityPlugin
    • @BrandonMinnick 谢谢,我遇到了一些问题,怀疑是 CrossCurrentActivity 的原因,但情况有所不同。
    • 另外,还有很多你的其他site 没有的错别字和错误。
    【解决方案3】:

    对于 iOS:

    if (UITraitCollection.CurrentTraitCollection.UserInterfaceStyle == UIUserInterfaceStyle.Dark)
    { ... }
    

    【讨论】:

      猜你喜欢
      • 2019-10-20
      • 2020-01-16
      • 2019-01-11
      • 2021-03-25
      • 2019-10-17
      • 1970-01-01
      • 2021-11-06
      • 2021-04-06
      • 2020-05-15
      相关资源
      最近更新 更多