James Montemagno
James Montemagno

Live, Love, Bike, and Code.

Live, Love, Bike, and Code

Share


Tags


James Montemagno

Xamarin.Forms: Drop Shadow/Elevation on Android Bottom Navigation TabbedPage

It is a tale as old of time fighting with Android elevation and drop shadows. First it was the Toolbar on a Navigation page and now it is the new fancy bottom tabs that we got in Xamarin.Forms 3.1. I know what you are thinking... another custom renderer... NOPE! You just have to know to set a few different properties correctly.

BeforeAfter

Here is what we are starting with:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
             android:TabbedPage.ToolbarPlacement="Bottom" 
             x:Class="GeoContacts.View.HomePage">
<!-- Pages Here-->
</TabbedPage>

As we can see there is no fancy shadow or elevation :(

Screenshot_20190211-164745

That Background Color!

The BottomNavigationView is a tricky beast regardless if you are in Android XML or Xamarin.Forms. To get a drop shadow/elevation on it you MUST set the background color! It is true, I even mentioned it way back in August 2017 when I wrote my original blog on it. All we need to do is set the background color on our TabbedPage and we are set:

BarBackgroundColor="{OnPlatform Android=White}"

And here we go:

Screenshot_20190211-163121

That is literally it! You can of course set it to any color you would like and you should still see a nice shadow appear to separate out your content. Now if for some reason you have to support a really really old device that doesn't support elevation, then you will have to do some custom work here. Don't worry as you can custom render it :)

Custom Android Layouts & Renderer

To do this manually you will need to create 2 resource files:

The shadow.xml is a very simple reverse gradient:

<?xml version="1.0" encoding="utf-8" ?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="#1F000000"
        android:endColor="@android:color/transparent"
        android:angle="90" />
</shape>

For the view_shadow.axml this is just a dummy view with the background set to shadow.

<View
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="4dp"
    android:background="@drawable/shadow"/>

Now, it is time for our custom renderer inside of our Android project. This code is actually very simple and just injects the view_shadow onto the top of our navigation view:

using Android.Views;
using Xamarin.Forms.Platform.Android.AppCompat;
using Xamarin.Forms.Platform.Android;
using Android.Support.Design.Widget;
using Android.Content;
using Android.Widget;

[assembly: ExportRenderer(typeof(TabbedPage), typeof(MyTabsRenderer))]
namespace GeoContacts.Droid
{
    public class MyTabsRenderer : TabbedPageRenderer
    {
        public MyTabsRenderer()
        {

        }
        public MyTabsRenderer(Context context)
        {

        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.TabbedPage> e)
        {
            base.OnElementChanged(e);

            if (!(GetChildAt(0) is ViewGroup layout))
                return;

            if (!(layout.GetChildAt(1) is BottomNavigationView bottomNavigationView))
                return;
            
            var topShadow = LayoutInflater.From(Context).Inflate(Resource.Layout.view_shadow, null);

            var layoutParams =
                new Android.Widget.RelativeLayout.LayoutParams(LayoutParams.MatchParent, 15);
            layoutParams.AddRule(LayoutRules.Above, bottomNavigationView.Id);

            layout.AddView(topShadow, 2, layoutParams);

        }
    }
}

There you have it! Regardless of your implementation the shadow adds some nice flare and takes minimal effort.

Live, Love, Bike, and Code

Checkout my monthly newsletter that you should subscribe to!

Copyright © James Montemagno 2019 All rights reserved. Privacy Policy

View Comments