Sharpnado.Tabs

repository·main·Indexed 20 days ago

https://github.com/roubachof/sharpnado.tabs

A highly customizable tab navigation library for .NET MAUI supporting Material Design, bottom bars, segmented controls, and vertical tabs. It utilizes a decoupled architecture consisting of TabHostView for the UI container and ViewSwitcher for content management, synchronized via SelectedIndex. The library includes performance optimizations like LazyView and DelayedView, as well as support for notification badges via BadgeView and custom actions using TabButton.

Tokens
6K
Snippets
19
Records
28
Agent score
68%

What's inside Sharpnado.Tabs

  1. Implement tabs using TabHostView and ViewSwitcher

    main

    Sharpnado.Tabs uses a two-part system to manage navigation:

    1. TabHostView: The UI container for the tab bar itself. It holds various TabItem implementations (like BottomTabItem or UnderlinedTabItem) and manages the visual state of the tabs. You should bind its SelectedIndex to a ViewSwitcher to synchronize the tab selection with the content view.

    2. ViewSwitcher: The container for the actual content views. It listens to the SelectedIndex and switches between its child views. To optimize performance, you can wrap your views in LazyView (loads when first needed) or DelayedView (loads after a delay, optionally showing an activity indicator).

    <!-- 1. The Tab Bar -->
    <tabs:TabHostView 
        SelectedIndex="{Binding Source={x:Reference Switcher}, Path=SelectedIndex, Mode=TwoWay}" 
        TabType="Fixed">
        <tabs:BottomTabItem Label="Home" />
        <tabs:BottomTabItem Label="Settings" />
    </tabs:TabHostView>
    
    <!-- 2. The Content Switcher -->
    <tabs:ViewSwitcher x:Name="Switcher" SelectedIndex="{Binding SelectedViewModelIndex, Mode=TwoWay}">
        <tabs:LazyView x:TypeArguments="views:HomeView" />
        <tabs:DelayedView x:TypeArguments="views:SettingsView" />
    </tabs:ViewSwitcher>
  2. How TabHostView and ViewSwitcher work together

    main

    The library uses a decoupled architecture where the tab navigation and the content display are separate components. They are connected via two-way binding on the SelectedIndex property.

    • TabHostView: The container for the tab controls. It manages the layout (Fixed or Scrollable), orientation (Horizontal or Vertical), and visual style (e.g., IsSegmented).
    • ViewSwitcher: The container for the actual content. It switches views based on the SelectedIndex provided by the TabHostView.

    This separation allows you to place the TabHostView and ViewSwitcher in different parts of your UI layout while maintaining synchronized navigation.

  3. Create custom tab items by extending TabItem

    main

    If the built-in tab items do not meet your design requirements, you can create custom tabs by extending the abstract TabItem class.

    // In your C# code
    public class MyCustomTab : TabItem
    {
        // Implement custom logic or properties here
    }
    <!-- In your XAML -->
    <tabs:TabHostView>
        <tabs:TabHostView.Tabs>
            <local:MyCustomTab Label="Custom" />
        </tabs:TabHostView.Tabs>
    </tabs:TabHostView>
  4. Performance optimization with LazyView and DelayedView

    main

    To improve app startup time and reduce UI construction overhead, the library provides components to defer view creation:

    • LazyView: Delays the creation of a view until it is actually needed.
    • DelayedView: An evolution of LazyView that allows for configurable delay timing and includes built-in support for an activity indicator during the loading process.
  5. Implement tabs using TabHostView and ViewSwitcher

    main

    To create a functional tabbed interface, use TabHostView (the UI for selecting tabs) and ViewSwitcher (the container that swaps the actual content views).

    These two components are independent and do not need to be adjacent. They are linked via their SelectedIndex property. The recommended pattern is to bind both to a single SelectedIndex property in your ViewModel to ensure they stay in sync.

    <!-- The Tab Selection UI -->
    <tabs:TabHostView x:Name="TabHost"
                      SelectedIndex="{Binding SelectedViewModelIndex, Mode=TwoWay}">
        <tabs:TabHostView.Tabs>
            <tabs:UnderlinedTabItem Label="Tab 1" />
            <tabs:UnderlinedTabItem Label="Tab 2" />
        </tabs:TabHostView.Tabs>
    </tabs:TabHostView>
    
    <!-- The Content Swapper -->
    <tabs:ViewSwitcher x:Name="Switcher"
                       SelectedIndex="{Binding SelectedViewModelIndex, Mode=TwoWay}">
        <views:ViewOne />
        <views:ViewTwo />
    </tabs:ViewSwitcher>
  6. Build and run the Sample Applications

    main

    The repository includes sample projects to demonstrate library features. You can build the main sample app, specific platform versions, or the Shell sample using the following commands.

    # Build the main sample app in Debug mode
    dotnet build MauiSample/MauiSample.csproj -c Debug
    
    # Build for specific platforms
    dotnet build MauiSample/MauiSample.csproj -f net9.0-android -c Debug
    dotnet build MauiSample/MauiSample.csproj -f net9.0-ios -c Debug
    dotnet build MauiSample/MauiSample.csproj -f net9.0-maccatalyst -c Debug
    
    # Restore dependencies for the sample solution
    dotnet restore MauiSample/MauiSample.sln
    
    # Build the Shell sample
    dotnet build MauiShellSample/MauiShellSample.csproj -c Debug
  7. Build the Sharpnado.Tabs library

    main

    Use the following commands to build the library from the root directory. Note that running a Release build automatically creates a NuGet package because PackOnBuild=true is enabled.

    # Build the main library in Release mode (also creates NuGet package)
    dotnet build Maui.Tabs/Maui.Tabs.csproj -c Release
    
    # Build the main library in Debug mode
    dotnet build Maui.Tabs/Maui.Tabs.csproj -c Debug
    
    # Explicitly create NuGet package
    dotnet pack Maui.Tabs/Maui.Tabs.csproj -c Release
  8. Optimize performance with DelayedView

    main

    To reduce application startup time, wrap your views inside a ViewSwitcher with DelayedView. This defers the UI building of components by a configurable number of milliseconds.

    DelayedView can be used anywhere in your app, not just within the Tabs context.

    <tabs:ViewSwitcher SelectedIndex="{Binding SelectedIndex}">
        <tabs:DelayedView x:TypeArguments="views:MyView"
                          AccentColor="Red"
                          Animate="True"
                          UseActivityIndicator="True" />
        <tabs:LazyView x:TypeArguments="views:OtherView" />
    </tabs:ViewSwitcher>
  9. Initialize Sharpnado.Tabs in MauiProgram.cs

    main

    To use the library, you must initialize it in your MauiProgram.cs using the .UseSharpnadoTabs() extension method on the MauiAppBuilder.

    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .UseSharpnadoTabs(loggerEnable: false);
    
            return builder.Build();
        }
    }
  10. Access Sharpnado.Tabs resources

    main

    The following resources are available for using and supporting the library:

    • NuGet Package: Install via NuGet using the package name Sharpnado.Tabs.Maui.
    • Sample Project: View the source code for the demonstration app in the MauiSample directory.
    • Issues & Support: Report bugs or request features on the GitHub Issues page.
  11. Initialize Sharpnado.Tabs in a .NET MAUI application

    main

    To use the library in your .NET MAUI project, you must call .UseSharpnadoTabs() during the application builder initialization in your MauiProgram.cs file. This enables the library's core functionality.

    Set loggerEnable to true if you need internal library logging, or false for production environments.

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseSharpnadoTabs(loggerEnable: false);
    
        return builder.Build();
    }