SkillAgentSearch skills...

Sharpnado.MaterialFrame

A modern MAUI frame component supporting blur, acrylic, dark mode. Implemented with RealtimeBlurView on Android (custom blurview) and UIVisualEffectView on iOS.

Install / Use

/learn @roubachof/Sharpnado.MaterialFrame
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Sharpnado.MaterialFrame

Presentation

Supported platforms

| | | | - | - | | <img src="Docs/material_frame_maui.png" height="150"> | Nuget <br/><br/> :heavy_check_mark: Android <br/> :heavy_check_mark: iOS <br/> :heavy_check_mark: MacCatalyst <br/> :heavy_check_mark: WinUI |

Initialization

  • In MauiProgram.cs:
public static MauiApp CreateMauiApp()
{
    var builder = MauiApp.CreateBuilder();
    builder
        .UseMauiApp<App>()
        .UseSharpnadoMaterialFrame(loggerEnable: false)
        ...
}

Version 3.0 - What's New

Version 3.0 brings a complete overhaul of the MaterialFrame architecture with major improvements:

https://github.com/user-attachments/assets/cd1bdeda-9c55-484a-938f-88ef2acbf26a

Handler Migration

All platforms have been migrated from the old Renderer pattern to modern MAUI Handlers:

  • Android: ContentViewHandler
  • iOS: ContentViewHandler
  • MacCatalyst: ContentViewHandler (full support added!)
  • Windows: ViewHandler<MaterialFrame, Grid>

Benefits: Better performance, cleaner code, better maintainability, and future-proof architecture.

Android Blur Revolution

Breaking Change: Replaced RenderScript with StackBlur algorithm

Why?

RenderScript was deprecated by Google and completely broken on Android 15+ devices with 16KB page size (crashes on Pixel 8 and newer devices).

The Solution: StackBlur

  • Pure C# implementation - No native dependencies, works on ALL Android versions including 15+
  • Async background processing - Blur runs on background thread with double buffering
  • Change detection - Skips blur when content hasn't changed (0% CPU when static)
  • Smooth performance - UI thread blocking reduced from ~22ms to ~3ms
  • 60 FPS scrolling - No more frame drops during animations

Performance Metrics

| Metric | Before (RenderScript) | After (StackBlur) | |--------|----------------------|-------------------| | Android 15+ compatibility | 💥 Broken | ✅ Works | | UI thread time | ~22ms | ~3ms | | Static content CPU | 100% | 0% | | Frame rate | 30-45 FPS | 60 FPS | | Blur quality | Excellent | Excellent |

New Features

  • MacCatalyst Support: Full blur support on Mac with shared iOS handler
  • Better Memory Management: Improved resource cleanup across all platforms
  • PropertyMapper: Declarative property handling for better performance

Migration Guide

No breaking changes in the API! Your existing XAML and code will work as-is. The improvements are all under the hood.

The only change: Android now uses StackBlur instead of RenderScript, which means:

  • ✅ Works on Android 15+
  • ✅ No more crashes on 16KB page size devices
  • ✅ Better performance overall

Android Compatibility issues

Warning, because of LayerDrawable the Acrylic glow effect (the white glow on the top of the MaterialFrame is only available on API 23+ (since Marshmallow).

Presentation

The MAUI MaterialFrame delivers out of the box modern popular theming:

  • Light
  • Dark
  • Acrylic
  • AcrylicBlur

You can switch from one theme to another thanks to the MaterialTheme property.

Switch

MaterialTheme

Light

In light theme, you can set the LightThemeBackgroundColor and control the Elevation.

<img src="Docs/frame_light.png" width="460" />

Dark

In dark theme, you can only control the Elevation, more elevation equals more light on the black frame (see below).

<img src="Docs/frame_dark.png" width="460" />

Acrylic

In Acrylic theme, you can still set the LightThemeBackgroundColor, also a Color of F1F1F1 is advised to have a good Acrylic effect.

<img src="Docs/frame_acrylic.png" width="460" />

AcrylicBlur

In AcrylicBlur theme, LightThemeBackgroundColor and Elevation properties are discarded.

You can set the BlurStyle property for both Android and iOS.

REMARK: On Android, the blur uses a pure C# StackBlur implementation that's optimized with async processing and change detection. It's performant but still a CPU operation, so use it wisely.

Light

<img src="Docs/frame_blur_light.png" width="460" />

ExtraLight

<img src="Docs/frame_blur_extralight.png" width="460" />

Dark

<img src="Docs/frame_blur_dark.png" width="460" />

WinUI specific properties

WinUI is the home of the Acrylic effect \o/

WinUIBlurOverlayColor

WinUI only.

Changes the overlay color over the blur (should be a transparent color, obviously). If not set, the different blur style styles take over.

Android specific properties

Because the Android version is a custom blur implementation, you have access to some fine tuning properties.

AndroidBlurOverlayColor

Android only.

Changes the overlay color over the blur (should be a transparent color, obviously). If not set, the different blur style styles take over.

AndroidBlurRadius

Android only.

Changes the blur radius on Android. If set, it takes precedence over MaterialBlurStyle. If not set, the different blur style styles take over.

AndroidBlurRootElement (Performance)

Android only: the root element must be an ancestor of the MaterialFrame.

Blur computation is very costly on Android since it needs to process all the view hierarchy from the root element to be blurred (most of the time the element displaying the underlying image) to the blur frame. The shorter the path, the better the performance. If no root element is set, the activity decor view is used.

Android handler configuration

You can configure the Android handler with static properties:

BlurUpdateIntervalMs

Minimum interval in milliseconds between blur updates. This throttles blur processing to prevent infinite loops and reduce CPU usage.

#if ANDROID
// In MauiProgram.cs or App.xaml.cs
AndroidMaterialFrameHandler.BlurUpdateIntervalMs = 16;  // 60fps - smoother
AndroidMaterialFrameHandler.BlurUpdateIntervalMs = 32;  // 30fps - default (balanced)
AndroidMaterialFrameHandler.BlurUpdateIntervalMs = 50;  // 20fps - battery saver
#endif

Default: 32ms (~30fps) - Good balance between smoothness and battery life

Use cases:

  • 16ms (60fps): Smooth animations, gaming scenarios
  • 32ms (30fps): General UI, recommended default
  • 50ms+ (20fps): Static content, battery-critical apps
BlurProcessingDelayMilliseconds

Delay before starting blur processing after view attachment. Sometimes the computation of the background can take some time (svg images for example). Setting a bigger delay ensures that the background is rendered first and can fix some glitches.

The Android implementation includes:

  • StackBlur: Pure C# blur algorithm (no native dependencies)
  • Async processing: Blur runs on background thread with double buffering
  • Change detection: Skips blur when content hasn't changed (0% CPU when static)
  • Time throttling: Configurable update interval prevents infinite loops
  • Performance: UI thread blocking reduced from ~22ms to ~3ms

LightThemeBackgroundColor

The background color in Light and Acrylic themes. In Dark theme, this value is ignored because the background color depends on the Elevation. In AcrylicBlur, the value is discarded cause iOS doesn't allow you to control the overlay color. Note that setting the BackgroundColor property has no effect with the MaterialFrame.

AcrylicGlowColor

You can change the "glow" of a MaterialFrame with an acrylic theme (the thin top white glow). Default is white. This property is ignored is the theme is not set to Acrylic.

Elevation

This property semantic changes according to the theme currently set:

Light Theme

Cast a shadow according to Google's Material elevation specs.

Dark Theme

Change the frame's background color according to Google's dark mode specs:

<img src="Docs/dark_elevation.png" width="460" />

Acrylic Theme

Property is ignored and a custom shadow is applied.

AcrylicBlur Theme

Property is ignored, no shadow is cast.

CornerRadius

Sets the corner radius of the frame (default: 5).

Changing theme for every frames

You either use DynamicResource as explained in my previous post.

Or use the static method called ChangeGlobalTheme(Theme newTheme). Setting a new theme on this method will change the MaterialTheme of every MaterialFrame of your app.

Examples of styles

Acrylic style

<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:sh="clr-namespace:Sharpnado.MaterialFrame;assembly=Sharpnado.MaterialFrame">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Colors.xaml" />
    </ResourceDictionaries.MergedDictionaries>

    <Style TargetType="sh:MaterialFrame">
        <Setter Property="MaterialTheme" Value="Acrylic" />
        <Setter Property="Margin" Value="5, 5, 5, 10" />
        <Setter Property="Padding" Value="20,15" />
        <Setter Property="CornerRadius" Value="10" />
        <Setter Property="LightThemeBackgroundColor" Value="{StaticResource AcrylicFrameBackgroundColor}" />
    </Style>

</ResourceDictionary>

Colors.xaml file:

<?xml version="1.0" encoding="UTF-8" ?>

<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <Color x:Key="AcrylicSurface">#E6E6E6</Color>

    <Color x:Key="AcrylicFrameBackgroundColor">#F1F1F1</Color>

    <Color x:Key="AccentColor">#00E000</Color>

Related Skills

View on GitHub
GitHub Stars516
CategoryCustomer
Updated16d ago
Forks31

Languages

C#

Security Score

95/100

Audited on Mar 12, 2026

No findings