Sharpnado.MaterialFrame for macOS

Get it from Github and Nuget:

https://github.com/roubachof/Sharpnado.MaterialFrame

Hello World ✌

hello.png

My name is Joachim Leonfellner, online I usually go by nor0x or johnny_leo. I'm an indie developer based in Vienna, Austria but trying to be remote as much as possible so traveling is one of my main hobbies. I'm in love with side-projects and learning and currently focus on everything dotnet.

Why Sharpnado.MaterialFrame?

I'm building a side-project which uses Xamarin.Forms (porting to dotnet MAUI already started) and i needed some fancy UI that goes a bit further than the built-in visuals. As an active follower of the Xamarin community Sharpnado was not new to me, so I started looking into Sharpnado.MaterialFrame. It's a great package and covered almost all of my needs for transparency with blurring and acrylics on iOS, Android and UWP. Another platform that i'm targeting with my project is macOS via Xamarin.Mac where i wanted to have controls like these:

controls.png

I knew that macOS has some built-in APIs for transparency, vibrancy and blurring so i decided to port the iOS renderer for Sharpnado.MaterialFrame to macOS.

First implementation

I began by looking at the code and how the iOS part of Sharpnado.MaterialFrame was implemented. Soon i found out that it's powered by CoreGraphics and CoreAnimation.
I have done macOS development in the past so i already knew about these frameworks and how they work across platforms like iOS and macOS so i thought the port of the iOSMaterialFrameRenderer wouldn't be high effort.

I started by copying the iOS renderer and removing frameworks that are not available on macOS - this was mostly about removing references to UIKit and replacing these with the AppKit counterparts, which is an easy task. For most of the UIKit components there is an AppKit equivalent with just the class prefix changed from UI to NS for example:
- UIColor becomes NSColor

It's nice that the API between UIKit and AppKit is so similar that porting functionality for color, size or rectangle is almost no effort. But also the blur and acrylic functionality was not really hard to port, since macOS has a very similar material API to implement such effects in NSVisualEffectView. Compared to UIVisualEffectView the AppKit version has a blend-mode property which controls the order of the effects, for desktop scenarios it can be useful not only blur content within the app but also add effects to the contents behind the window. This behavior can be controlled via NSVisualEffectBlendingMode which is currently set to WithinWindow for Sharpnado.MaterialFrame.

nsvisualeffects.png

Very similar to UIKit there are also various blur styles on macOS, they are in an enum called NSVisualEffectMaterial. It contains the values ExtraLight, Light and Dark which are needed for Sharpnado.MaterialFrame. Compared to UIKit it also has some desktop specific materials for example Titlebar, Sidebar or Popover .

Gotchas

Most of the logic to display the blur and acrylic effect is not on the level of the view (UIView or NSView) but one level deeper on the _intermediateLayer which is of type CALayer and can be used without much modification on iOS and macOS - however there is one gotcha i ran into when building the macOS renderer. The vertical axis of the coordinate system is flipped on macOS compared to iOS. For the material frame on macOS this means that the ShadowOffset property of the layer has be flipped to match the visual representation of the iOS implementation.

coordinates.png

PRing my changes

When i had my first implementation of the macOSMaterialFrameRenderer i forked the Sharpnado.Acrylic repository and added a macOS project to see if the renderer works and renders all the properties and modes that are supported. When i was happy with the rendering and tweaks i created a PR to Sharpnado.Acrylic and Sharpnado.MaterialFrame. I have also created a local NuGet so that i can start using my implementation until my PR was merged.

Ship it ⛵!

In the PR we discussed some visual tweaks and after a few commits i was ready to do complete my implementation with the administrative stuff like updating the nuspec file and adding a macOS specific section the the repository readme. It was a great experience to collaborate with @roubachof on this awesome piece of software. From now on i'm using the official NuGet of Sharpnado.MaterialFrame with the macOS bits in my projects.

Here is Sharpnado.Acrylic running on macOS using the native API for blurring and acrylic effects.

output.gif

For my current usecase this is enough functionality, but who knows - maybe i'll update the macOS specifics of Sharpnado.MaterialFrame in the future with more desktop specific functionality.