SimpleToolkit

repository·main·Indexed 20 days ago

https://github.com/radekvym/simpletoolkit

A modular collection of helpers and lightweight .NET MAUI controls for granular UI and navigation control. It includes SimpleShell, a decoupled alternative to the standard MAUI Shell for custom navigation experiences; SimpleButton, a Border-based button that supports arbitrary content and VisualStateManager feedback; and SimpleToolkit.Helpers, featuring the WindowInsetsProvider for cross-platform handling of safe areas and system bars on Android, iOS, Mac Catalyst, and Windows.

Tokens
14.9K
Snippets
32
Records
44
Agent score
67%

What's inside SimpleToolkit

  1. Overview of SimpleToolkit

    main

    SimpleToolkit is a collection of helpers and lightweight, customizable .NET MAUI controls designed to provide developers with full control over application UI and navigation. It is modular, allowing you to install only the specific packages you need.

    Supported Platforms:

    • Android
    • iOS / Mac Catalyst
    • Windows (WinUI)
  2. Define Visual Structure and Navigation Hosts in SimpleShell

    main

    A SimpleShell app's visual structure is defined using containers.

    • Content property: A container that wraps the entire content of the app. Use this for elements that should be visible on every single page (e.g., a global Header or a persistent Back button).
    • SimpleNavigationHost: The specific view that acts as the hosting area for pages. You must include exactly one SimpleNavigationHost within your container hierarchy.

    You can manually define custom app bars and tab bars by placing elements within the Content container and using SimpleNavigationHost to reserve the space where pages will be rendered.

    <simpleShell:SimpleShell ...>
        <simpleShell:SimpleShell.Content>
            <Grid RowDefinitions="50, *, 50">
                <!-- Global Header/Back Button -->
                <Button x:Name="backButton" Text="Back" />
                
                <!-- Page Hosting Area -->
                <simpleShell:SimpleNavigationHost Grid.Row="1"/>
                
                <!-- Custom Tab Bar -->
                <HorizontalStackLayout Grid.Row="2" ... />
            </Grid>
        </simpleShell:SimpleShell.Content>
    </simpleShell:SimpleShell>
  3. Choose between Platform-specific and Universal transitions in SimpleShell

    main

    When using SimpleShell, you must choose between two mutually exclusive types of page transitions. You cannot combine them in a single application; you must commit to one approach for the entire project.

    1. Platform-specific transitions: These leverage the native transitions provided by the underlying platform APIs and controls. These are the default behavior.
    2. Universal transitions: These are fully cross-platform transitions implemented using only .NET MAUI APIs, ensuring consistent behavior across all supported platforms.
  4. Understand SimpleShell limitations and trade-offs

    main

    While SimpleShell provides significantly more flexibility than the standard .NET MAUI Shell, developers should be aware of the following trade-offs:

    • Platform-Native Aesthetics: Standard Shell uses native OS looks; SimpleShell uses custom-composed views.
    • Performance: Standard Shell uses native navigation controls which may be more optimized than custom-composed .NET MAUI views.
    • Accessibility: Standard Shell has built-in accessibility; SimpleShell requires manual implementation to meet accessibility standards.
    • Maturity: As a custom implementation, SimpleShell may have edge cases not present in the official MAUI components.
  5. Customize container views with ShellGroupContainerTemplate

    main

    You can specify a custom container view for each ShellItem or ShellSection using the SimpleShell.ShellGroupContainerTemplate attached property. This allows you to define a DataTemplate that creates a container on demand during navigation.

    Key Requirements:

    • The view defined in the template must include a SimpleNavigationHost element in its hierarchy to act as the placeholder for root pages.
    • Once initialized, the created view is cached in the SimpleShell.ShellGroupContainer property for reuse.
    • The BindingContext of the view inside the template is the respective ShellSection (or Tab) instance.

    This is useful for creating custom navigation bars (like top tabs) that live within a specific section of the shell.

    <Tab
        Title="Yellow-Green"
        Route="YellowGreenTab">
        <simpleShell:SimpleShell.ShellGroupContainerTemplate>
            <DataTemplate
                x:DataType="ShellSection">
                <Grid
                    RowDefinitions="50, *">
                    <!-- Custom UI like a top tab bar -->
                    <HorizontalStackLayout
                        Margin="20,5"
                        HorizontalOptions="Start" Spacing="10"
                        BindableLayout.ItemsSource="{Binding Items}">
                        <BindableLayout.ItemTemplate>
                            <DataTemplate x:DataType="BaseShellItem">
                                <Button Text="{Binding Title}" Clicked="ShellItemButtonClicked" />
                            </DataTemplate>
                        </BindableLayout.ItemTemplate>
                    </HorizontalStackLayout>
    
                    <!-- REQUIRED: The placeholder for pages -->
                    <simpleShell:SimpleNavigationHost
                        Grid.Row="1"/>
                </Grid>
            </DataTemplate>
        </simpleShell:SimpleShell.ShellGroupContainerTemplate>
    
        <ShellContent Title="Yellow" ContentTemplate="{DataTemplate pages:YellowPage}" Route="YellowPage"/>
        <ShellContent Title="Green" ContentTemplate="{DataTemplate pages:GreenPage}" Route="GreenPage"/>
    </Tab>
  6. Use the SimpleShellTransition class

    main

    A SimpleShellTransition object represents a universal transition. It is configured via its constructor using the following properties:

    • Callback: A method called as the transition progress changes. It receives SimpleShellTransitionArgs.
    • Starting: A method called when the transition begins.
    • Finished: A method called when the transition completes.
    • Duration: Returns the duration of the transition.
    • DestinationPageInFront: Returns whether the destination page should be displayed in front of the origin page.
    • Easing: Returns the easing function for the animation.

    Each of these properties accepts a delegate that receives SimpleShellTransitionArgs, which provides metadata about the currently running transition (such as TransitionType, Progress, OriginPage, and DestinationPage).

  7. Set transitions on pages or the Shell

    main

    Transitions can be applied at two levels:

    1. Global Default: Set a transition on your SimpleShell object to make it the default for all pages.
    2. Page-Specific: Set a transition on an individual Page using the SetTransition extension methods. A page-specific transition will override the global default.

    Important: When navigating, the transition of the destination page is the one that is played.

  8. Use RootPageContainer for top-level only elements

    main

    If you want certain navigation elements (like tab bars or floating action buttons) to be visible only on top-level screens and hidden when navigating to detail pages, use the RootPageContainer.

    • The RootPageContainer is a wrapper view that applies exclusively to your root pages (ShellContents).
    • The RootPageContainer must contain a SimpleNavigationHost element somewhere in its hierarchy to host the root pages.
    • When navigating to a detail page (a route not part of the root hierarchy), the contents of RootPageContainer will no longer be visible.
    <simpleShell:SimpleShell ...>
        <!-- Elements here are only visible on root pages -->
        <simpleShell:SimpleShell.RootPageContainer>
            <Grid RowDefinitions="*, 50">
                <simpleShell:SimpleNavigationHost/>
                <HorizontalStackLayout Grid.Row="1" ... />
            </Grid>
        </simpleShell:SimpleShell.RootPageContainer>
    
        <!-- Elements here are visible on EVERY page -->
        <simpleShell:SimpleShell.Content>
            <Grid RowDefinitions="50, *">
                <Button Text="Back" />
                <simpleShell:SimpleNavigationHost Grid.Row="1"/>
            </Grid>
        </simpleShell:SimpleShell.Content>
    </simpleShell:SimpleShell>
  9. How SimpleShell navigation hierarchy works

    main

    SimpleShell provides a decoupled implementation of the .NET MAUI Shell navigation model. It manages the logical structure of your app but does not provide UI controls (like TabBars or Flyouts). You are responsible for building the visual UI that interacts with the shell.

    Core Concepts

    • Logical Hierarchy: You define your app structure using ShellContent, Tab, TabBar, and FlyoutItem.
    • Interchangeable Items: In SimpleShell, TabBar and FlyoutItem are functionally interchangeable (both act as ShellItem). You can even use multiple TabBar elements simultaneously.
    • Implicit Wrappers: Like standard MAUI Shell, ShellItem and ShellSection wrappers can be omitted; they will be implicitly generated if you define Tab or ShellContent directly.
    • URI Navigation: It uses the standard .NET MAUI URI-based navigation scheme.
    <simpleShell:SimpleShell ...>
        <TabBar>
            <Tab Title="Yellow-Green" Route="YellowGreenTab">
                <ShellContent
                    Title="Yellow"
                    ContentTemplate="{DataTemplate pages:YellowPage}"
                    Route="YellowPage"/>
                <ShellContent
                    Title="Green"
                    ContentTemplate="{DataTemplate pages:GreenPage}"
                    Route="GreenPage"/>
            </Tab>
        </TabBar>
    </simpleShell:SimpleShell>
  10. How SimpleShell works and when to use it

    main

    Concept

    SimpleShell is a decoupled implementation of .NET MAUI Shell. It provides the standard URI-based navigation and stack management (Shell.Current.GoToAsync()) but removes the forced UI (TabBars, Flyouts, TitleBars).

    Instead of using the built-in UI, you define the logical hierarchy using standard Shell elements (ShellContent, Tab, TabBar, FlyoutItem), but you define the visual layout manually using the Content or RootPageContainer properties. The actual area where pages are rendered is provided by the SimpleNavigationHost view.

    When to use SimpleShell

    Choose SimpleShell if:

    • You need a completely custom design that native Shell doesn't allow.
    • You want a unified UI look across iOS, Android, and Windows.
    • You want to host the navigation area anywhere in your layout.

    Stick to .NET MAUI Shell if:

    • You want a 100% "Native" look and feel.
    • Out-of-the-box accessibility is your top priority.
    • You don't want to build your own TabBar/Flyout logic.
  11. Use Page type states to style based on Page class

    main

    You can apply visual states based on the actual type of the Page being navigated to. Use the naming convention SimplePageState.[Page type name] within a VisualStateGroup named SimplePageStates. This allows you to style the UI based on the class name of the current page (e.g., HomePage or SettingsPage).

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="SimplePageStates">
            <VisualState x:Name="SimplePageState.HomePage">
                <VisualState.Setters>
                    <Setter TargetName="tabBar" Property="View.Background" Value="Purple"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="SimplePageState.SettingsPage">
                <VisualState.Setters>
                    <Setter TargetName="tabBar" Property="View.Background" Value="Orange"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
  12. Use ShellSection states to style ShellSections

    main

    You can apply visual states to your UI based on which ShellSection is currently active. Use the naming convention SimpleShellSectionState.[ShellSection route] within a VisualStateGroup named SimpleShellSectionStates. This allows you to trigger property changes (like background colors) on specific views when a user navigates to a particular tab or section route.

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="SimpleShellSectionStates">
            <VisualState x:Name="SimpleShellSectionState.HomeTab">
                <VisualState.Setters>
                    <Setter TargetName="tabBar" Property="View.Background" Value="Red"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="SimpleShellSectionState.SettingsTab">
                <VisualState.Setters>
                    <Setter TargetName="tabBar" Property="View.Background" Value="Green"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>