adospace/reactorui-maui

Adding triggers to a style

Mithgroth opened this issue · 2 comments

Hey man,
currently I'm battling with an iOS MAUI bug with TabBar.

Long story short, TabBar doesn't highlight the selected item on iOS as it does on Android.

Somebody suggested a workaround here, it requires a Style with Trigger.

I'm not sure how to do this in MauiReactor since Triggers IList of Style is readonly, is there a way to define/set triggers to a style?

Hi, you can define the style in a resource dictionary and reference it in the Style property.

I've created a sample project:
https://github.com/adospace/mauireactor-samples/blob/main/Controls/ShellTestPage/Pages/MainPage8.cs

basically, you have to define the styles like the following FixTabStyles.xaml:

<Style x:Key="FixIOSDatabaseTabStyle" TargetType="Tab">
     <Style.Triggers>
         <Trigger TargetType="Tab" Property="IsChecked" Value="True">
             <Setter Property="Icon">
                 <Setter.Value>
                     <FontImageSource 
                        Size="20"
                        Color="{DynamicResource Primary}"
                        Glyph="{x:Static styles:AwesomeIconFont.Database}"
                        FontFamily="FontSolid"/>
                 </Setter.Value>
             </Setter>
         </Trigger>

         <Trigger TargetType="Tab" Property="IsChecked" Value="False">
             <Setter Property="Icon">
                 <Setter.Value>
                     <FontImageSource 
                        Size="20" 
                        Color="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}"
                        Glyph="{x:Static styles:AwesomeIconFont.Database}"
                        FontFamily="FontSolid"/>
                 </Setter.Value>
             </Setter>
         </Trigger>
     </Style.Triggers>
 </Style>

reference it in the app resources:

                .UseMauiReactorApp<MainPage8>(app =>
                {
                    app.AddResource("Resources/Styles/FixTabStyles.xaml");
                })

finally use it in the component:

public override VisualNode Render()
      => Shell(
          TabBar(
              Tab(
                  ShellContent("Notifications")
                      .RenderContent(() => new NotificationsPage())
              )
              .OnAndroid(_ => _.Icon(new MauiControls.FontImageSource 
                  {
                      FontFamily = "FontSolid",
                      Glyph = AwesomeIconFont.Bell,
                      Size = 20,
                  }))
              .OniOS(_=>_.Style(ResourceManager.FindStyle("FixIOSNotificationsTabStyle")))

              .Title("Notifications"),

              Tab(
                  ShellContent()
                      .RenderContent(() => new DatabasePage())
              )
              .OnAndroid(_ => _.Icon(new MauiControls.FontImageSource
              {
                  FontFamily = "FontSolid",
                  Glyph = AwesomeIconFont.Database,
                  Size = 20,
              }))
              .OniOS(_ => _.Style(ResourceManager.FindStyle("FixIOSDatabaseTabStyle")))

              .Title("Database")
          ));

the resource manager:

static class ResourceManager
{
    static readonly Dictionary<string, object> _cachedResources = [];

    public static T Find<T>(string name) where T : class
    {
        if (_cachedResources.TryGetValue(name, out var value))
        {
            return (T)value;
        }

        if (Application.Current != null &&
            Application.Current.Resources != null)
        {
            var foundResource = Application.Current.Resources.Find<T>(name);
            _cachedResources.Add(name, foundResource);
            return foundResource;
        }

        return null;        
    }

    public static T Find<T>(this ResourceDictionary resourceDictionary, string name) where T : class
    {
        if (resourceDictionary.TryGetValue(name, out var value))
        {
            return (T)value;
        }

        foreach (var mergedDictionary in resourceDictionary.MergedDictionaries)
        {
            var foundResource = mergedDictionary.Find<T>(name);
            if (foundResource != null)
            {
                return foundResource;
            }
        }

        return null!;
    }

    public static Style FindStyle(string name)
        => Find<Style>(name);
    
}

Please note that I can't test it on mac right now.

PS: probably I'm going to enhance the Style property in coming versions of MauiReactor to better handle resources that are located in dictionaries, something like what ResoureManager above does.

Tested on iOS Simulator, works good, thanks man.
Also +1 for Style enhancements.