【问题标题】:How to change the status bar color without a navigation page如何在没有导航页面的情况下更改状态栏颜色
【发布时间】:2020-02-14 20:58:21
【问题描述】:

我想更改某些视图的状态栏颜色。

我找到了这个解决方案https://github.com/yuv4ik/XFDynamicStatusBarAppearance

但它只适用于 NavigationPage。

我不需要从我的应用导航页面...

    public App()
    {
        InitializeComponent();

        MainPage = new MainPage();
    }

这是我的尝试...

    var statusBarStyleManager = DependencyService.Get<IStatusBarStyleManager>();

    MainCarousel.PositionChanged += (sender, e) =>
    {
        switch (e.CurrentPosition)
        {
            case 1:
                Device.BeginInvokeOnMainThread(() =>
                {
                    Xamarin.Forms.Application.Current.MainPage.SetValue(Xamarin.Forms.NavigationPage.BarBackgroundColorProperty, Color.DarkCyan);

                    //((Xamarin.Forms.NavigationPage)Xamarin.Forms.Application.Current.MainPage).BarBackgroundColor = Color.DarkCyan;
                    statusBarStyleManager.SetDarkTheme();
                });
                break;
            case 0:
            case 2:
                Device.BeginInvokeOnMainThread(() =>
                {
                    Xamarin.Forms.Application.Current.MainPage.SetValue(Xamarin.Forms.NavigationPage.BarBackgroundColorProperty, Color.LightGreen);
                    statusBarStyleManager.SetLightTheme();
                });
                break;
            default:
                break;
        }
    };

如何更改状态栏颜色?

【问题讨论】:

  • 我不认为你可以用纯 Xamarin.Forms 做到这一点。正如@Cherry Bu - MSFT 所说,您将不得不使用 DependencyService,并在 Android 和 iOS 中分别实现它。可以在此处找到 iOS 解决方案:forums.xamarin.com/discussion/89840/…。如果您在实施时遇到问题,请告诉我们:)
  • 谢谢@Julipan,这个链接很有帮助!!

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


【解决方案1】:

这是我在两个平台上的工作解决方案...

public interface IStatusBarStyleManager
{
    void SetColoredStatusBar(string hexColor);
    void SetWhiteStatusBar();
}

用这一行设置状态栏颜色

DependencyService.Get<IStatusBarStyleManager>().SetColoredStatusBar("#2196F3");

或者你可以用黑色字体颜色保持白色

DependencyService.Get<IStatusBarStyleManager>().SetWhiteStatusBar();

安卓

[assembly: Xamarin.Forms.Dependency(typeof(StatusBarStyleManager))]
namespace ShaXam.Droid.DependencyServices
{
    public class StatusBarStyleManager : IStatusBarStyleManager
    {
        public void SetColoredStatusBar(string hexColor)
        {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    var currentWindow = GetCurrentWindow();
                    currentWindow.DecorView.SystemUiVisibility = 0;
                    currentWindow.SetStatusBarColor(Android.Graphics.Color.ParseColor(hexColor);
                });
            }
        }

        public void SetWhiteStatusBar()
        {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    var currentWindow = GetCurrentWindow();
                    currentWindow.DecorView.SystemUiVisibility = (StatusBarVisibility)SystemUiFlags.LightStatusBar;
                    currentWindow.SetStatusBarColor(Android.Graphics.Color.White);
                });
            }
        }

        Window GetCurrentWindow()
        {
            var window = CrossCurrentActivity.Current.Activity.Window;

            // clear FLAG_TRANSLUCENT_STATUS flag:
            window.ClearFlags(WindowManagerFlags.TranslucentStatus);

            // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
            window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);

            return window;
        }
    }
}

iOS

[assembly: Dependency(typeof(StatusBarStyleManager))]
namespace ShaXam.iOS.DependencyServices
{
    public class StatusBarStyleManager : IStatusBarStyleManager
    {
        public void SetColoredStatusBar(string hexColor)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
                if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
                {
                    statusBar.BackgroundColor = Color.FromHex(hexColor).ToUIColor();
                }
                UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false);
                GetCurrentViewController().SetNeedsStatusBarAppearanceUpdate();
            });
        }

        public void SetWhiteStatusBar()
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
                if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
                {
                    statusBar.BackgroundColor = UIColor.White;
                }
                UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.Default, false);
                GetCurrentViewController().SetNeedsStatusBarAppearanceUpdate();
            });
        }

        UIViewController GetCurrentViewController()
        {
            var window = UIApplication.SharedApplication.KeyWindow;
            var vc = window.RootViewController;
            while (vc.PresentedViewController != null)
                vc = vc.PresentedViewController;
            return vc;
        }
    }
}

发布更新以支持 IOS 13

[assembly: Dependency(typeof(StatusBarStyleManager))]
namespace ShaXam.iOS.DependencyServices
{
    public class StatusBarStyleManager : IStatusBarStyleManager
    {
        public void SetColoredStatusBar(string hexColor)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
                {
                    UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
                    statusBar.BackgroundColor = Color.FromHex(hexColor).ToUIColor();
                    UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
                }
                else
                {
                    UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
                    if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
                    {
                        statusBar.BackgroundColor = Color.FromHex(hexColor).ToUIColor();
                    }
                }
                UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false);
                GetCurrentViewController().SetNeedsStatusBarAppearanceUpdate();
            });
        }

        public void SetWhiteStatusBar()
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
                {
                    UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
                    statusBar.BackgroundColor = UIColor.White;
                    UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
                }
                else
                {
                    UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
                    if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
                    {
                        statusBar.BackgroundColor = UIColor.White;
                    }
                }
                UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.DarkContent, false);
                GetCurrentViewController().SetNeedsStatusBarAppearanceUpdate();
            });
        }

        UIViewController GetCurrentViewController()
        {
            var window = UIApplication.SharedApplication.KeyWindow;
            var vc = window.RootViewController;
            while (vc.PresentedViewController != null)
                vc = vc.PresentedViewController;
            return vc;
        }
    }
}

完整的工作示例在这里https://github.com/georgemichailou/ShaXam

【讨论】:

  • SystemUiVisibility 在 Android 11 中已过时。将其用于 API 30+: WindowInsetsControllerAppearance lightStatusBars = isLight ? WindowInsetsControllerAppearance.LightStatusBars:0; currentWindow.InsetsController?.SetSystemBarsAppearance((int)lightStatusBars, (int)lightStatusBars);
  • 嗨@G.Mich,您的解决方案适用于Android,但不适用于iOS,适用于管理DarkMode 的设备。当DarkMode被激活时,StatusBar的背景是白色的,但StatusBar的文字/信息也是白色的:所以它们被隐藏了......
  • 嗨@Gold.strike,检查我更新的代码!谢谢!!
  • @Gold.strike 谢谢,黑暗模式在这里产生了一些冲突......我尝试解决这个问题。
  • @Gold.strike 我修好了。 github.com/georgemichailou/ShaXam/commit/…
【解决方案2】:

@Cherry Bu 的回答 - MSFT 很棒,但有点过时了。 SystemUiVisibility 在 Android 11 中已过时,因此这里更新了 StatusBarStyleManager 以兼容新 API:

using Android.Graphics;
using Android.OS;
using Android.Views;
using Plugin.CurrentActivity;
using Xamarin.Essentials;

[assembly: Xamarin.Forms.Dependency(typeof(StatusBarStyleManager))]
namespace YourApp.Droid.Dependences
{
    public class StatusBarStyleManager : IStatusBarStyleManager
    {
        public void SetColoredStatusBar(string hexColor)
        {
            if (Build.VERSION.SdkInt < BuildVersionCodes.M)
            {
                return;
            }

            MainThread.BeginInvokeOnMainThread(() =>
            {
                var currentWindow = GetCurrentWindow();
                SetStatusBarIsLight(currentWindow, false);
                currentWindow.SetStatusBarColor(Color.ParseColor(hexColor));
                currentWindow.SetNavigationBarColor(Color.ParseColor(hexColor));
            });
        }

        public void SetWhiteStatusBar()
        {
            if (Build.VERSION.SdkInt < BuildVersionCodes.M)
            {
                return;
            }

            MainThread.BeginInvokeOnMainThread(() =>
            {
                var currentWindow = GetCurrentWindow();
                SetStatusBarIsLight(currentWindow, true);
                currentWindow.SetStatusBarColor(Color.White);
                currentWindow.SetNavigationBarColor(Color.White);
            });
        }

        private static void SetStatusBarIsLight(Window currentWindow, bool isLight)
        {
            if ((int)Build.VERSION.SdkInt < 30)
            {
#pragma warning disable CS0618 // Type or member is obsolete. Using new API for Sdk 30+
                currentWindow.DecorView.SystemUiVisibility = isLight ? (StatusBarVisibility)(SystemUiFlags.LightStatusBar) : 0;
#pragma warning restore CS0618 // Type or member is obsolete
            }
            else
            {
                var lightStatusBars = isLight ? WindowInsetsControllerAppearance.LightStatusBars : 0;
                currentWindow.InsetsController?.SetSystemBarsAppearance((int)lightStatusBars, (int)lightStatusBars);
            }
        }

        private Window GetCurrentWindow()
        {
            Window window = Platform.CurrentActivity.Window;
            window.ClearFlags(WindowManagerFlags.TranslucentStatus);
            window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
            return window;
        }
    }
}

附注:如果您还想更改状态栏的颜色,这里是您需要更改的行:

  • currentWindow.DecorView.SystemUiVisibility = isLight ? (StatusBarVisibility)(SystemUiFlags.LightStatusBar | SystemUiFlags.LightNavigationBar) : 0;
  • var lightStatusBars = isLight ? WindowInsetsControllerAppearance.LightStatusBars | WindowInsetsControllerAppearance.LightNavigationBars : 0;

更新 - 2021 年夏季

此代码(或多或少)现在是 Xamarin.CommunityToolkit 的一部分:https://github.com/xamarin/XamarinCommunityToolkit/pull/812。 我建议从那里使用它,如果有任何问题open an issue,所以它对每个人都是固定的。

目前 XCT 以 Android 10 为目标,因此没有 Android 11 相关代码,但当此逻辑迁移到 CommunityToolkit.Maui 时,Android 11 逻辑也将添加(XCT 和 CT.MAUI 在任何 Android 上都可以正常工作版本,只是想指出代码差异)

【讨论】:

  • 2021 年的最佳答案,因为它避免使用已弃用的属性 SystemUiVisibility
  • 您好,这似乎不适用于弹出详细信息页面。你知道怎么修改吗?
  • @ledragon 嗨,更新了答案以表明此代码现在是 XCT 的一部分。你能在那里打开一个问题吗?
【解决方案3】:

您可以尝试在Android平台添加此代码,OnCreate方法:

 protected override void OnCreate(Bundle savedInstanceState)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);

        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

        LoadApplication(new App());
       Window.SetStatusBarColor(Android.Graphics.Color.Argb(255, 0, 0, 0)); //here

    }

请注意,SetStatusBarColor 仅在 API 级别 21 及更高版本中受支持。因此,我们应该在调用 SetStatusBarColor 之前检查这一点。

if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)

  {
   Window.SetStatusBarColor(...);
  }

更新:

在 PCL 中创建接口:

public  interface IStatusBarColor
{
    void changestatuscolor(string color);
}

现在,Mainactivity 实现了这个接口。

[assembly: Dependency(typeof(demo2.Droid.MainActivity))]
 namespace demo2.Droid
 {
[Activity(Label = "demo2", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,IStatusBarColor
{

    public static Context context;
    protected override void OnCreate(Bundle savedInstanceState)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);

        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

        LoadApplication(new App());

    }



    public void changestatuscolor(string color)
    {
        if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
        {
            var c = MainActivity.context as FormsAppCompatActivity;
            c?.RunOnUiThread(() => c.Window.SetStatusBarColor(Android.Graphics.Color.ParseColor(color)));
        }

    }
    protected override void OnResume()
    {
        context = this;
        base.OnResume();
    }

}

}

在主页中,更改按钮单击事件中的状态栏颜色。

 private void Changecolor_Clicked(object sender, EventArgs e)
    {
        DependencyService.Get<IStatusBarColor>().changestatuscolor(Color.Red.ToHex());
    }

【讨论】:

  • 这与我所说的完全不同。我使用 Xamarin.Forms,我希望动态更改每个视图的状态颜色。你的答案是 Xamarin.Android 并且状态颜色设置是 OnCreate 方法.....
  • @G.Mich,你可以使用dependencyservice来做这个,请看我的更新。
  • @G.Mich,如果我的回复解决了您的问题,请记得将我的回复标记为答案,谢谢。
  • 对不起,这个答案只适用于安卓平台。无论如何感谢您的帮助!!!
【解决方案4】:

正如@maxc137 所说,此功能现在可在 Xamarin 社区工具包中使用。您只需将 Xamarin.CommunityToolkit 包添加到您的项目并设置状态栏颜色,如下所示:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="Example.Views.MyPage"
         xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
         xct:StatusBarEffect.Color="Red"
         Title="My Page">

如果要在所有页面上设置相同的颜色,则设置全局隐式样式:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
         x:Class="Example.App">
<Application.Resources>
    <ResourceDictionary>            
        <Style TargetType="ContentPage" ApplyToDerivedTypes="True">
            <Setter Property="xct:StatusBarEffect.Color" Value="Red"/>
        </Style>
    </ResourceDictionary>        
</Application.Resources>

【讨论】:

    猜你喜欢
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 2018-07-04
    • 1970-01-01
    • 1970-01-01
    • 2019-11-13
    • 2015-08-06
    • 1970-01-01
    相关资源
    最近更新 更多