如何在Xamarin表单中使用Light Theme?

问题描述

我更新了Visual Studio,现在我的程序主题与手机上的主题相同,电话上的内容暗了,我希望程序变亮,请帮忙,我尝试了Application.Current.UserAppTheme = OSAppTheme.Light,但不起作用

解决方法

您可以使用AppThemeBinding设置浅色主题或深色主题。

从下面的链接下载源文件并进行一些更改。 https://docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/userinterface-systemthemesdemo/

当您在手机上设置暗模式并希望程序变亮时,您可以如下更改xaml:

更改: ContentPage BackgroundColor

 BackgroundColor="{AppThemeBinding Light={StaticResource LightPageBackgroundColor},Dark={StaticResource DarkPageBackgroundColor}}">

收件人:

 BackgroundColor="{AppThemeBinding Light={StaticResource DarkPageBackgroundColor},Dark={StaticResource LightPageBackgroundColor}}">

更改::网格BackgroundColor

 <Grid BackgroundColor="{AppThemeBinding Light={StaticResource LightPrimaryColor},Dark={StaticResource DarkPrimaryColor}}">

收件人:

 <Grid BackgroundColor="{AppThemeBinding Light={StaticResource DarkPrimaryColor},Dark={StaticResource LightPrimaryColor}}">
,

动态更改属性

第一步是将将受主题更新影响的每个视图属性交换为StaticResource到DynamicResource。 这样做时,例如,当将DynamicBackgroundColor从黑色设置为白色时,它将自动传播到引用此键的所有属性。

让我们看看我们的App.xaml:

<Color x:Key="DarkSurface">#121212</Color>  
<Color x:Key="LightSurface">#00FF0266</Color>

...

<Style ApplyToDerivedTypes="True" TargetType="ContentPage">  
<Setter Property="Padding">
    <Setter.Value>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS">0,20,0</On>
            <On Platform="Android">0,0</On>
        </OnPlatform>
    </Setter.Value>
</Setter>
<Setter Property="BackgroundColor" Value="{DynamicResource DynamicBackgroundColor}" />
</Style>

<Style ApplyToDerivedTypes="True" TargetType="NavigationPage">  
    <Setter Property="BarBackgroundColor" Value="{DynamicResource 
                                                   DynamicNavigationBarColor}" />
    <Setter Property="BarTextColor" Value="{DynamicResource DynamicBarTextColor}" />
</Style>  

我们可以看到DynamicResource也可以使用样式...

DynamicResource值的不足之处在于您不会像经典的StaticResource这样的样式来定义它。 例如,在xaml中的任何地方都没有定义DynamicBackgroundColor,您可以将它们视为等待分配的引用。

您可以像这样在代码中动态分配它们(之后我们将看到SetDynamicResource实现):

// Dark Mode
SetDynamicResource(DynamicBackgroundColor,"DarkSurface");

// Ligh Mode
SetDynamicResource(DynamicBackgroundColor,"LightSurface"); 

在明暗模式之间切换

在我的愚蠢应用中!底部栏上有一个带有切换主题图标的TabButton,单击它会调用SetDarkMode()或SetLightMode():

namespace SillyCompany.Mobile.Practices.Presentation.Views{
   public static class ResourcesHelper{
        public const string DynamicPrimaryTextColor = nameof(DynamicPrimaryTextColor);
        public const string DynamicSecondaryTextColor = nameof(DynamicSecondaryTextColor);

        public const string DynamicNavigationBarColor = nameof(DynamicNavigationBarColor);
        public const string DynamicBackgroundColor = nameof(DynamicBackgroundColor);
        public const string DynamicBarTextColor = nameof(DynamicBarTextColor);

        public const string DynamicTopShadow = nameof(DynamicTopShadow);
        public const string DynamicBottomShadow = nameof(DynamicBottomShadow);

        public const string DynamicHasShadow = nameof(DynamicHasShadow);

        public const string Elevation4dpColor = nameof(Elevation4dpColor);

        ...

        public static void SetDynamicResource(string targetResourceName,string sourceResourceName)
    {
        if (!Application.Current.Resources.TryGetValue(sourceResourceName,out var value))
        {
            throw new InvalidOperationException($"key {sourceResourceName} not found in the resource dictionary");
        }

          Application.Current.Resources[targetResourceName] = value;
      }

      public static void SetDynamicResource<T>(string targetResourceName,T value)
      {
          Application.Current.Resources[targetResourceName] = value;
      }

      public static void SetDarkMode()
      {
           MaterialFrame.ChangeGlobalTheme(MaterialFrame.Theme.Dark);
           SetDynamicResource(DynamicNavigationBarColor,"DarkElevation2dp");
           SetDynamicResource(DynamicBarTextColor,"TextPrimaryDarkColor");

           SetDynamicResource(DynamicTopShadow,ShadowType.None);
           SetDynamicResource(DynamicBottomShadow,ShadowType.None);
           SetDynamicResource(DynamicHasShadow,false);

           SetDynamicResource(DynamicPrimaryTextColor,"TextPrimaryDarkColor");
           SetDynamicResource(DynamicSecondaryTextColor,"TextSecondaryDarkColor");

           SetDynamicResource(DynamicBackgroundColor,"DarkSurface");

           SetDynamicResource(Elevation4dpColor,"DarkElevation4dp");
       }

       public static void SetLightMode(){
           MaterialFrame.ChangeGlobalTheme(MaterialFrame.Theme.Light);
           SetDynamicResource(DynamicNavigationBarColor,"Accent");
           SetDynamicResource(DynamicBarTextColor,ShadowType.Top);
           SetDynamicResource(DynamicBottomShadow,ShadowType.Bottom);
           SetDynamicResource(DynamicHasShadow,true);

           SetDynamicResource(DynamicPrimaryTextColor,"TextPrimaryLightColor");
           SetDynamicResource(DynamicSecondaryTextColor,"TextSecondaryLightColor");

           SetDynamicResource(DynamicBackgroundColor,"LightSurface");

           SetDynamicResource(Elevation4dpColor,"OnSurfaceColor");
        }
   }
}

您可以看到,我不仅在改变颜色,而且还在黑暗模式下禁用阴影,因为黑暗模式本质上是平坦的。

示例: SillyBottomTabsPage.cs

<tb:Toolbar x:Name="Toolbar"  
        Title="Silly App!"
        BackgroundColor="{DynamicResource DynamicNavigationBarColor}"
        ForegroundColor="White"
        HasShadow="{DynamicResource DynamicHasShadow}"
        Subtitle="The Official sample app for the Sharpnado's components" />

...

<tabs:TabHostView   x:Name="TabHost"  
                Grid.Row="2"
                BackgroundColor="{DynamicResource Elevation4dpColor}"
                ShadowType="{DynamicResource DynamicTopShadow}"
                TabType="Fixed"
                SelectedIndex="{Binding Source={x:Reference Switcher},Path=SelectedIndex,Mode=TwoWay}">

<tabs:TabButton x:Name="TabButton"
                IsVisible="True"
                ButtonBackgroundColor="{StaticResource Accent}"
                ButtonCircleSize="60"
                ButtonPadding="15"
                IconImageSource="theme_96.png"
                Scale="1.3"
                TranslationY="-10"
                Clicked="TabButtonOnClicked" />

...

进行过渡 现在,让我们看一下过渡的代码:

SillyBottomTabsPage.xaml.cs

private void TabButtonOnClicked(object sender,EventArgs e){
    TaskMonitor.Create(AnimateTabButton);
}

private void ApplyTheme(){

   if (_currentTheme == Theme.Light) {
        ResourcesHelper.SetLightMode();
        return;
   }

   ResourcesHelper.SetDarkMode();
}

private async Task AnimateTabButton(){

    double sourceScale = TabButton.Scale;
    Color sourceColor = TabButton.ButtonBackgroundColor;
    Color targetColor = _currentTheme == Theme.Light
    ? ResourcesHelper.GetResourceColor("DarkSurface")
    : Color.White;

    // Bounce then remove icon from button,await TabButton.ScaleTo(3);
    await TabButton.ScaleTo(sourceScale);
    TabButton.IconImageSource = null;

    // Ballon inflation
    var bigScaleTask = TabButton.ScaleTo(30,length: 500);
    // Change color to target dark/light mode
    var colorChangeTask = TabButton.ColorTo(
    sourceColor,targetColor,callback: c => TabButton.ButtonBackgroundColor = c,length: 500);

    // run animation at the same time
    await Task.WhenAll(bigScaleTask,colorChangeTask);

    _currentTheme = _currentTheme == Theme.Light ? Theme.Dark : Theme.Light;
    ApplyTheme();

    // reverse inflation and color animation to accent color
    var reverseBigScaleTask = TabButton.ScaleTo(sourceScale,length: 500);
    var reverseColorChangeTask = TabButton.ColorTo(
    targetColor,sourceColor,c => TabButton.ButtonBackgroundColor = c,length: 500);

    await Task.WhenAll(reverseBigScaleTask,reverseColorChangeTask);

    // icon is back
    TabButton.IconImageSource = "theme_96.png";
}