MaterialFrame leveled up with a Blur theme!

Get it from Github and Nuget:
![]() |
https://github.com/roubachof/Sharpnado.MaterialFrame |
Sharpnado.MaterialFrame
gets its own github repository to showcase all its theming power:
- Blur
- Acrylic
- Dark
- Light
The Blur theme supports 3 different blur styles based on iOS UIVisualEffectView
:
- Light
- Dark
- ExtraLight
On Android it has advanced blur customization:
AndroidBlurOverlayColor
AndroidBlurRadius
AndroidBlurRootElement
(Performance)
Read the doc on https://github.com/roubachof/Sharpnado.MaterialFrame.
Hey man this is not Acrylic!
James tweeted about its ongoing Animal Crossing turnip stock options pricing app (sorry I'm a dota 2 player :):
Been jamming on some UI for my #AnimalCrossing app. Switched over to #Sharpnado tabs from @Piskariov and fancy Acrylic UI :) Looks really nice :) pic.twitter.com/vMSmMtCeD6
— James Montemagno (@JamesMontemagno) April 9, 2020
Then someone replied with the most incredible outrageous message.
Well he was totally right :)
Acrylic effect is a blur effect with some kind of opacity, and it was next on my list for the MaterialFrame
.
Dynamic theming in the Silly! app
Implementation journey
For iOS
, the implementation was really easy: it's just supported by the UIVisualEffectView
.
I just had to add this kind of view as a sub view of my native iOS UIView
and it was it :)
For Android
, well, it was a hell of a journey.
I did my research, and found two solid candidates:
For the first one, there even was a xamarin binding:
Since my android renderer is implemented with a CardView
(which is a FrameLayout
), I thought BlurView
was the closest to it (it also inherits from FrameLayout
).
Since the implementation was really small, I just converted the java code to C# code. It removes the reference to another nuget package, and you can really adjust it to your needs.
After a lot of testing, turned out that it was less usable and solid that I thought.
First it works badly if you just use it in a UI hierarchy behind another view, it kinds of blur together the background elements and some front elements...
Also the rendering was sometimes flickering.
So I just disabled the BlurView
implementation and traded it with the RealtimeBlurView
.
The implementation for the RealtimeBlurView
is simpler and made by a solid member of the Android
community.
It went smoothly till I stumbled upon a Xamarin.Android
bug:
https://github.com/xamarin/xamarin-android/issues/4548
Causing SIGSEV
while debugging.
To overcome this issue I created a special Android configuration property:
AndroidMaterialFrameRenderer.ThrowStopExceptionOnDraw
=> If set to true
, the rendering result could be better (clearer blur not mixing front elements).
However due to a bug in the Xamarin
framework https://github.com/xamarin/xamarin-android/issues/4548, debugging is impossible with this mode (causes SIGSEGV).
My suggestion would be to set it to false for debug, and to true for releases.
If you're not debugging the app won't crash but annoying UNHANDLED EXCEPTION will be spammed in the logs.
So I created another issue for this:
https://github.com/xamarin/xamarin-android/issues/4632
It is a weird error caused by an Exception thrown in java runtime and caught in C# runtime:
public class StopException : Exception {} // same result if RuntimeException
public class RealtimeBlurView : View
{
....
public override void Draw(Canvas canvas)
{
if (mIsRendering)
{
if (AndroidMaterialFrameRenderer.ThrowStopExceptionOnDraw)
// Quit here, don't draw views above me
throw STOP_EXCEPTION;
return;
}
if (RENDERING_COUNT > 0)
{
// Doesn't support blurview overlap on another blurview
}
else
{
base.Draw(canvas);
}
}
}
...
class PreDrawCallback : ViewTreeObserver.IOnPreDrawListener
{
public bool OnPreDraw()
{
try
{
...
decor.Draw(blurView.mBlurringCanvas);
// |=> throws custom StopException since BlurView is an indirect child of decor
// |=> monodroid is logging "UNHANDLED EXCEPTION + StopException <stack trace>"
}
catch(Exception e)
{
// the code here is executed, so the exception, is handled
// even if monodroid logs the unhandled exception
}
}
}
Anyway, this was an issue for me, but it won't be one for the users of the MaterialFrame
, all those scenarios are taken care of with the ThrowStopExceptionOnDraw
android property.
As said, just set it to to false during debugging sessions, and to true in RELEASE
(or DEBUG
without debugger attached).
As written above, if the property is set to false, the draw
method will just return without interrupting the draw chain (no StopException
is thrown). So elements in front of the blurred view will also be mixed in the blur.