Nalu.Maui

repository·main·Indexed 42 days ago

https://github.com/nalu-development/nalu

A suite of libraries for .NET MAUI development featuring a replacement for MAUI Shell called the Scaffold, a high-performance VirtualScroll alternative to CollectionView, and a fluent, type-safe MVVM navigation service. Includes advanced XAML layout primitives, specialized controls like DurationWheel and InteractableCanvasView, and core utilities for iOS background HTTP requests and soft-keyboard management.

Tokens
92.6K
Snippets
228
Records
305
Agent score
54%

What's inside Nalu.Maui

  1. Overview of Nalu.Maui Key Modules

    main

    Nalu.Maui is composed of several specialized modules:

    • Navigation: A fluent, type-safe MVVM navigation service. Features include relative/absolute navigation, guards, typed intents, a built-in leak detector, and source-generated page registration via AddPages(). It supports MAUI Shell, NaluShell, and the Scaffold.
    • VirtualScroll: A high-performance alternative to CollectionView built on native RecyclerView (Android) and UICollectionView (iOS). It handles thousands of dynamically-sized rows smoothly. Note: This module is dual-licensed (Non-Commercial/Commercial).
    • Layouts: Advanced XAML primitives including ToggleTemplate, TemplateBox, SlideBox, ExpanderViewBox, ViewBox, and Magnet (a constraint-based layout system).
    • Controls: Specialized cross-platform controls like DurationWheel and InteractableCanvasView.
    • Core: Common utilities such as NSUrlBackgroundSessionHttpMessageHandler (iOS background HTTP) and a soft-keyboard manager.
  2. What is Magnet layout

    main

    Magnet is a constraint-based layout engine where every child is positioned by anchoring its sides to other children, virtual nodes (barriers, guidelines, chains), or the parent stage. It follows a mental model similar to Android's ConstraintLayout but allows for a flat hierarchy, avoiding the need for nested layouts.

    Magnet 2.0 uses a compiled constraint graph (an instruction tape) to achieve high performance with zero allocations during measure/arrange cycles.

  3. What is the Nalu Scaffold?

    main

    The Scaffold is a complete replacement for the standard MAUI Shell on iOS and Android. It provides a fully customizable application shell where every piece of chrome (tab bar, nav bar, drawers, popups, bottom sheets) is a standard MAUI view that can be restyled or replaced.

    Key features include:

    • Shared element transitions between pages.
    • Per-page drawers and bottom sheets.
    • Scroll-driven chrome and system-bar styling.
    • Support for iOS edge-swipe and Android predictive back (using a seekable choreography).
    • Integration with Nalu navigation, ensuring guards, lifecycle, and state restoration work correctly.
  4. Understand the per-page navigation bar model

    main

    In the current architecture, the navigation bar is no longer a shared strip controlled at the controller level. Instead, the navigation bar is part of each page's individual presentation. It is mounted inside each page's host container, meaning it moves in sync with the page during all scaffold motions (such as push/pop slides, custom ScaffoldPageTransition specs, shared elements, interactive pop, Android predictive back, and modal presentation).

    Key characteristics:

    • Library-owned chrome: Uses the same ScaffoldNavBarHost, appearance chain, scroll tracker, and default ScaffoldNavBarView (or custom NavBarView).
    • No shared strip mode: The concept of a single controller-level strip or virtual bar swap has been removed.
    • Page Insets: A page's top inset is derived from its own navigation bar immediately and finally before the page is staged. Page insets are not animated during navigation (though they may animate during same-page visibility toggles).
    • Unchanged components: The tab bar (shared bottom chrome), overlays (popups, sheets, panels, flyouts), OverlayEvent, and NavigationEvent remain unchanged.
  5. How automatic disposal and scoped services work in Nalu

    main

    Nalu Navigation manages a ServiceScope for each navigated page.

    • Scoped Lifetimes: Pages and ViewModels are registered as Scoped. Any service registered as AddScoped<T> will live only as long as the page is in the navigation stack.
    • Automatic Disposal: When a page is removed from the navigation stack, Nalu automatically disposes of the page, the ViewModel, and all scoped services. If you implement IDisposable, it is called after the page is removed and the navigation animation completes.
    // This service lives only while the page is in the navigation stack
    builder.Services.AddScoped<IPageSpecificService, PageSpecificService>();
  6. Understand Scaffold runtime changes and Hot Reload

    main

    The Areas and Roots in a Scaffold are observable and can be modified at runtime:

    • Adding Roots: New roots appear in the UI chrome and become navigable.
    • Removing Roots: If the current root is removed, the engine automatically navigates to a fallback root before completing the removal.
    • XAML Hot Reload: Supported end-to-end. Re-inflating the scaffold adopts existing navigation stacks by segment, meaning page state (navigation history, view models) survives the reload. TabBarView swaps also apply live.
  7. iOS Lock Screen timer display limitations

    main

    When designing Live Activities for iOS, be aware of two OS-level rendering behaviors on the Lock Screen:

    1. Always-On Display: In reduced-luminance mode, the system masks seconds. A ticking clock will render as 1:--, updating only the minutes. Full luminance restores the seconds.
    2. Interval-based text: Some timer text styles (like plain .timer) may degrade to coarse relative strings (e.g., "1 minute") on the Lock Screen instead of ticking every second. Ensure your custom widget design accounts for this.
  8. How Popups work in Nalu.Maui

    main

    In Nalu.Maui, Popups are implemented as ContentPages with a transparent background. Nalu provides a PopupPageBase class that simplifies this by automatically creating a modal page with a background scrim (overlay) and a styled container for your content.

    To customize the look and feel of all popups in your application, you should define global styles for nalu:PopupScrim (the background overlay) and nalu:PopupContainer (the content box) in your Styles.xaml file.

    <!-- Example global styles in Styles.xaml -->
    <Style TargetType="nalu:PopupScrim">
        <Setter Property="BackgroundColor" Value="#20000000" />
    </Style>
    
    <Style TargetType="nalu:PopupContainer">
        <Setter Property="Background" Value="White" />
        <Setter Property="StrokeShape" Value="RoundRectangle 24" />
        <Setter Property="VerticalOptions" Value="Center" />
        <Setter Property="HorizontalOptions" Value="Center" />
    </Style>
  9. Perform relative and absolute navigation

    main

    Nalu distinguishes between Relative navigation (modifying the current stack) and Absolute navigation (changing the root or shell structure).

    Relative Navigation

    Used for pushing, popping, or replacing pages within the current stack.

    • Push<T>(): Adds a page to the stack.
    • Pop(): Removes the top page.
    • Pop().Push<T>(): Replaces the current page.

    Absolute Navigation

    Used for navigating to specific ShellContent items.

    • Root<T>(): Switches the entire navigation root to a specific page.
    • Root<T>().Add<U>(): Navigates to a root and then pushes a page onto that new stack.
    // Relative examples
    Navigation.Push<DetailPageModel>(new DetailIntent(42)); // Push with intent
    Navigation.Pop(new EditResult(saved: true));           // Pop with result
    Navigation.Pop().Push<NewPageModel>();                // Replace
    
    // Absolute examples
    Navigation.Root<MainPageModel>();                      // Switch root
    Navigation.Root<SettingsPageModel>().Add<DetailPageModel>(); // Root + Push
    Navigation.Absolute().Root<MainPageModel>("custom-route"); // Custom route
  10. Understand the per-page navigation bar model

    main

    Nalu is moving to a model where each page has its own dedicated navigation bar. Instead of a single global navigation bar managed by the Scaffold, each page is wrapped in a ScaffoldPageHost.

    Key Concepts:

    • ScaffoldPageHost: A logical, non-visual Element that acts as the parent of a Page. It manages the page's specific navigation bar (ScaffoldNavBarHost), the bar's context (ScaffoldNavBarContext), and properties like IsNavBarVisible and NavBarOverlapsContent.
    • ScaffoldNavBarContext: A per-page object containing navigation state (e.g., CanNavigateBack, IsModal, IsCloseButtonVisible). The Scaffold.NavBarContext property now acts as a forwarder to the current page's context.
    • ScaffoldNavBarHost: The UI component that renders the navigation bar for a specific page. It is a logical child of the ScaffoldPageHost and is only present in the element tree when the bar is visible.

    Lifecycle:

    • A ScaffoldPageHost is created when a page enters the navigation stack (via ScaffoldNavigationStack.Push or setting RootPage) and is disposed when the page leaves the stack.
    • Pages remaining in the stack (not currently visible) keep their ScaffoldPageHost alive, allowing their navigation bars to maintain state.
  11. Scaffold Navigation Behavior and Differences

    main

    Understanding how Scaffold differs from MAUI Shell:

    • Engine-Routed Navigation: Every navigation, including tab taps, is routed through the Nalu engine. This means navigation guards (like ILeavingGuard) will be triggered by tab switches, unlike native Shell behavior.
    • Safe Areas: Scaffold automatically manages insets. Page content should use standard SafeAreaEdges per edge. The navigation bar footprint contributes to insets unless NavBarOverlapsContent is set.
    • Back Button Handling: Page.OnBackButtonPressed is not supported for hosted pages as it only fires for hardware back. For all leave-path confirmation logic (including on-screen pops), use ILeavingGuard.
    • Android Back: Uses the predictive-back dispatcher (compatible with Android 16+).
    • State Preservation: Tab switches preserve stacks, scroll offsets, and entry text, matching NaluShell semantics.
  12. Handle visibility in Magnet 2.0

    main

    Magnet 2.0 tracks visibility by reading the IView.Visibility of the bound view (e.g., IsVisible="False" will cause the view to collapse).

    Additionally, a node can declare ApplyVisibility="Hide" or ApplyVisibility="Show". This is a one-shot action applied to the view's IsVisible property when the definition is applied (similar to ConstraintSet-style scenes).