The Problem
Imagine scenario: You wake up in the morning fully rested.. You go to your desk and press magic "On" button on your Dell, while the computer does the heavy lifting on a really important Windows 11 update, you make espresso doppio, a favorite one. You sit down to your desk with your warm coffee. You click on Zeplin icon to see newest design for app you're developing and you see this:
And you're like:
Rounded TabBar with shadow!? How could it be?
Don't worry 😁 I have working solution for you (but only for iOS for now).
Solution
Since I'm using Shell in my project I had to create custom renderer for AppShell type.
Just copy paste it into Xamarin.iOS project
using CoreAnimation;
using CoreGraphics;
using Invoize;
using TabBarCustomControl.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(AppShell), typeof(ShellWithCustomTabBar))]
namespace TabBarCustomControl.iOS
{
internal class ShellWithCustomTabBar : ShellRenderer
{
protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker()
{
return new CustomTabbarAppearance();
}
}
public class CustomTabbarAppearance : ShellTabBarAppearanceTracker
{
private IShellAppearanceElement _shellAppearance;
public override void SetAppearance(UITabBarController controller, ShellAppearance appearance)
{
base.SetAppearance(controller, appearance);
_shellAppearance = appearance as IShellAppearanceElement;
}
public override void UpdateLayout(UITabBarController controller)
{
//remove shape and background color of Tabbar
controller.View.BackgroundColor = UIColor.White;
controller.TabBar.BackgroundImage = UIImageExtensions.FromColor(UIColor.Clear);
controller.TabBar.ShadowImage = new UIImage();
// apply custom shadow
var backgroundColor = _shellAppearance.EffectiveTabBarBackgroundColor.ToUIColor();
controller.TabBar.MakeCornerTabBar(UIColor.Black, backgroundColor, 1F, UIRectCorner.TopLeft | UIRectCorner.TopRight, new CGSize(-5, 3), 20);
}
}
internal static class UIImageExtensions
{
//from UIColor
public static UIImage FromColor(UIColor color)
{
var rect = new CGRect(0, 0, 1, 1);
UIGraphics.BeginImageContext(rect.Size);
var context = UIGraphics.GetCurrentContext();
context.SetFillColor(color.CGColor);
context.FillRect(new CGRect(0, 0, rect.Width, rect.Height));
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image;
}
}
internal static class UIViewExtensions
{
public static UIView MakeCornerTabBar(this UIView uIView, UIColor shadowColor, UIColor fillColor, float opacity, UIRectCorner corners, CGSize offset, float radious)
{
var shadowLayer = new CAShapeLayer();
shadowLayer.Path = UIBezierPath.FromRoundedRect(uIView.Bounds, corners, new CGSize(radious, radious)).CGPath;
shadowLayer.FillColor = fillColor.CGColor;
shadowLayer.ShadowColor = shadowColor.CGColor;
shadowLayer.ShadowPath = shadowLayer.Path;
shadowLayer.ShadowOffset = offset;
shadowLayer.ShadowOpacity = opacity;
shadowLayer.ShadowRadius = 5;
shadowLayer.BackgroundColor = UIColor.Clear.CGColor;
shadowLayer.BorderColor = UIColor.Clear.CGColor;
shadowLayer.StrokeColor = UIColor.Clear.CGColor;
shadowLayer.FillRule = CAShapeLayer.FillRuleEvenOdd;
uIView.Layer.InsertSublayer(shadowLayer, 0);
return uIView;
}
}
}
Result
This is how it affects default Shell Tabbed template
Conclusion
Conclusion is one: subscribe to be notified when Android implementation lands 😎
Cheers!