Xamarin.Forms:如何在AppShell中设置FlyoutItems中图标的颜色

Xamarin.Forms: How to set the Color of Icons in FlyoutItems in AppShell

我正在使用 AppShell 实现一个 Xamarin.Forms 应用程序,但似乎无法弄清楚如何在 Flyout 菜单中设置选定/未选定图标的颜色。这是我认为控制行为的 appshell.xaml 部分(我使用各种高对比度颜色来显示哪些设置控制了什么)。 (完整代码示例:https://github.com/wadebaird/ShellExample 供更多参考):

<Style x:Name="FlyoutItem" Class="FlyoutItemLayoutStyle" TargetType="Layout" ApplyToDerivedTypes="True">
        <Setter Property="VisualStateManager.VisualStateGroups">
            <VisualStateGroupList>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Normal">
                        <VisualState.Setters>
                            <!-- This is the color of the unselected text for the labels in the flyout-->
                            <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="Magenta" />
                            <Setter TargetName="FlyoutItemLabel" Property="Label.BackgroundColor" Value="Cyan" />
                            <!-- This is the background color of the selected icon in the flyout -->
                            <Setter Property="BackgroundColor" Value="Green" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Selected">
                        <VisualState.Setters>
                            <!-- This is the color of the selected text in the flyout -->
                            <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="Black"/>
                            <Setter TargetName="FlyoutItemLabel" Property="Label.BackgroundColor" Value="Yellow" />
                            <!-- This is the background color of the selected icon in the flyout -->
                            <Setter Property="BackgroundColor" Value="Red" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateGroupList>
        </Setter>
    </Style>

这是这些设置的视觉效果。在此图像中,“顶部的实体是”选定的“项目。我希望/希望图标与文本的颜色相匹配,但似乎找不到设置。

以下是我要展示的图标“白色”是如何不起作用的:

我可以在 FontImageSource 上手动设置颜色,但它总是那个颜色,并且与选定/未选定的颜色不匹配:

<ShellContent Route="aboutPage" Title="About" ContentTemplate="{DataTemplate views:AboutPage}" >
    <ShellContent.Icon>
        <FontImageSource Size="{StaticResource FlyoutIconSize}" Color="Black" Glyph="{x:Static fontAwesome:FontAwesomeIcons.InfoCircle}" FontFamily="FA-Solid" />
    </ShellContent.Icon>
</ShellContent>

我在“普通状态”-“正常”/“已选择”中尝试了各种类似的东西,但没有任何效果。:

<Setter Property="FontImageSource.Color" Value="{AppThemeBinding Light={StaticResource PrimaryUnselectedTextColorLight}, Dark={StaticResource PrimaryUnselectedTextColorDark}}" />

附带说明(这可能是一个错误)。在 iOS 上显示,当第一次打开弹出窗口时,没有任何内容被“选中”:

在 Android 上,选择了正确的项目:

我知道这是一个单独的项目,如果我找不到现有的 issue/bug,我会记录一个错误,但我想我会提到它,因为有人知道我的答案上面可能已经意识到这个问题了。

您可以使用Shell.ItemTemplate设置标签和图标的背景颜色。并使用 VisualStateGroup 更改选中状态的颜色。

Shell.ItemTemplate:

   <Shell.ItemTemplate>
    <DataTemplate>
        <Grid ColumnDefinitions="0.2*,0.8*" ColumnSpacing="0" Style="{StaticResource FloutItemStyle}">
            <Image  x:Name="FlyoutItemIcon"  Source="{Binding FlyoutIcon}" HeightRequest="45" />
            <Label x:Name="FlyoutItemLabel"   Grid.Column="1"
                   Text="{Binding Title}"
                   FontAttributes="Italic"
                   VerticalTextAlignment="Center" />
        </Grid>
    </DataTemplate>
</Shell.ItemTemplate>

风格:

 <Style  x:Key="FloutItemStyle" Class="FlyoutItemLayoutStyle" TargetType="Layout" ApplyToDerivedTypes="True">
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal">
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor" Value="{x:OnPlatform UWP=Transparent, iOS=White}" />
                                <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource Primary}" />
                                <Setter TargetName="FlyoutItemLabel" Property="Label.BackgroundColor" Value="Blue" />
                                <Setter TargetName="FlyoutItemIcon" Property="Image.BackgroundColor" Value="Green" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Selected">
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor" Value="{StaticResource Primary}" />
                                <Setter TargetName="FlyoutItemLabel" Property="Label.BackgroundColor" Value="{StaticResource Primary}" />
                                <Setter TargetName="FlyoutItemIcon" Property="Image.BackgroundColor" Value="{StaticResource Primary}" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>
        </Style>

在 Wendy Zang 的部分解决方案之后(它解决了背景颜色但没有解决前景),它让我走上了正确的轨道 我能够找到 , which utilized two labels instead of an image. (I also tried to use the Image that Wendy suggested above and an effect like the IconTintColorEffect.TintColor from this ,但我无法让它正常工作,因为图标的大小对于图像来说要复杂得多。)

我尝试了将不同类型的派生 classes 与 IconGlyph 属性 搭配使用的解决方案,我让它运行良好,但我不喜欢它的简洁性。然后我想到使用 IValueConverter 来修复标签 class:

的绑定
public class FlyoutGlyphConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return null;

        if (value is not BaseShellItem baseShellItem)
            throw new ArgumentException($"This converter may only be used on values of type {nameof(BaseShellItem)}.");

        if (baseShellItem.Icon is not FontImageSource fontImageSource)
            throw new ArgumentException($"This converter may only be used on values of type {nameof(BaseShellItem)}s with Icons of type {nameof(FontImageSource)}.");

        return fontImageSource.Glyph;
    }
}

而我的 xaml 结果是这样的:

<Shell.ItemTemplate>
    <DataTemplate x:DataType="root:IShellIconFont">
        <Grid Margin="0" Padding="0" ColumnSpacing="0">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroupList>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal">
                            <VisualState.Setters>
                                <!-- This is the color of the unselected text for the labels in the flyout-->
                                <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="#2196F3" />
                                <Setter TargetName="FlyoutItemLabel" Property="Label.BackgroundColor" Value="White" />
                                <!-- This is the background color of the selected icon in the flyout -->
                                <Setter TargetName="FlyoutItemIcon" Property="Image.BackgroundColor" Value="White" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Selected">
                            <VisualState.Setters>
                                <!-- This is the color of the selected text in the flyout -->
                                <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="White"/>
                                <Setter TargetName="FlyoutItemLabel" Property="Label.BackgroundColor" Value="#2196F3" />
                                <!-- This is the background color of the selected icon in the flyout -->
                                <Setter TargetName="FlyoutItemIcon" Property="Image.BackgroundColor" Value="#2196F3" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </VisualStateManager.VisualStateGroups>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.2*" />
                <ColumnDefinition Width="0.8*" />
            </Grid.ColumnDefinitions>
            <Label x:Name="FlyoutItemIcon" Grid.Column="0" FontFamily="FA-Solid" FontSize="{StaticResource FlyoutIconSize}"
                    Text="{Binding ., Converter={StaticResource FlyoutGlyph}}" TextColor="{Binding Source={x:Reference FlyoutItemLabel}, Path=TextColor}"
                    VerticalTextAlignment="Center" HorizontalTextAlignment="Center"
                    Margin="0" Padding="0"/>
            <Label x:Name="FlyoutItemLabel" Grid.Column="1" Text="{Binding Title}" FontSize="{StaticResource FlyoutLabelFontSize}" 
                    FontAttributes="Bold" VerticalTextAlignment="Center" HeightRequest="45" />
        </Grid>
    </DataTemplate>
</Shell.ItemTemplate>
<FlyoutItem Route="root" Title="Entitys" FlyoutDisplayOptions="AsMultipleItems">
    <root:ShellContentIconFont Route="mainPage" Title="Entity" Glyph="{x:Static fontAwesome:FontAwesomeIcons.BookOpen}" ContentTemplate="{DataTemplate views:MainPage}" />
    <root:ShellContentIconFont Route="favoritesPage" Title="Favorites" Glyph="{x:Static fontAwesome:FontAwesomeIcons.Star}" ContentTemplate="{DataTemplate views:FavoritesPage}" />
    <root:TabIconFont Route="entitys" Title="Entitys" Glyph="{x:Static fontAwesome:FontAwesomeIcons.Book}" >
        <ShellContent Route="entitysCalendar" Title="Calendar" ContentTemplate="{DataTemplate views:EntitysCalendarPage}" />
        <ShellContent Route="entitysList" Title="List" ContentTemplate="{DataTemplate views:EntitysListPage}" />
    </root:TabIconFont>
</FlyoutItem>
<FlyoutItem Route="root" Title="Entitys" FlyoutDisplayOptions="AsMultipleItems">
    <ShellContent Route="mainPage" Title="Entity" ContentTemplate="{DataTemplate views:MainPage}">
        <ShellContent.Icon>
            <FontImageSource Size="{StaticResource FlyoutIconSize}" Glyph="{x:Static fontAwesome:FontAwesomeIcons.BookOpen}" FontFamily="FA-Solid" />
        </ShellContent.Icon>
    </ShellContent>
    <ShellContent Route="favoritesPage" Title="Favorites" ContentTemplate="{DataTemplate views:FavoritesPage}">
        <ShellContent.Icon>
            <FontImageSource Size="{StaticResource FlyoutIconSize}" Glyph="{x:Static fontAwesome:FontAwesomeIcons.Star}" FontFamily="FA-Solid" />
        </ShellContent.Icon>
    </ShellContent>
    <Tab Route="entitys" Title="Entitys">
        <Tab.Icon>
            <FontImageSource Size="{StaticResource FlyoutIconSize}" Glyph="{x:Static fontAwesome:FontAwesomeIcons.Book}" FontFamily="FA-Solid" />
        </Tab.Icon>
        <ShellContent Route="entitysCalendar" Title="Calendar" ContentTemplate="{DataTemplate views:EntitysCalendarPage}" />
        <ShellContent Route="entitysList" Title="List" ContentTemplate="{DataTemplate views:EntitysListPage}" />
    </Tab>
</FlyoutItem>
<ShellContent Route="aboutPage" Title="About" ContentTemplate="{DataTemplate views:AboutPage}" >
    <ShellContent.Icon>
        <FontImageSource Size="{StaticResource FlyoutIconSize}" Glyph="{x:Static fontAwesome:FontAwesomeIcons.InfoCircle}" FontFamily="FA-Solid" />
    </ShellContent.Icon>
</ShellContent>

这是最终结果:

另一方面,此解决方案中的某些内容修复了 iOS 问题,即在初始打开时未选择任何内容。我猜这是定义的 DataTemplate。