Create rounded custom TabBar with shadow in Xamarin.Forms (iOS)

Create rounded custom TabBar with shadow in Xamarin.Forms (iOS)

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:

Your honest reaction

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!

Show Comments