0
votes

I'm using a MasterDetailPage, where both the Menu and the Content page have a white background. So I need to add a shadow separator to the Content page when the menu is showing. Like this:

enter image description here

The only example I could find is this: https://gist.github.com/SeeD-Seifer/120971b4dda7a785a7f4bda928c9dc2b

I've implemented the code, and the shadow effect works on Labels, Images and other elements. But I cannot get it to work on a NavigationPage.

My code:

ShadowEffect.cs

public class ShadowEffect : RoutingEffect
{
    public float Radius { get; set; }
    public Color Color { get; set; }
    public float DistanceX { get; set; }
    public float DistanceY { get; set; }
    public ShadowEffect() : base("MyCompany.PanelShadowEffect")
    {
    }
}

ShadowNavigationPage.cs

public ShadowNavigationPage(Page root) : base(root)
{

}

protected override void OnAppearing()
{
    base.OnAppearing();

    Effects.Add(new ShadowEffect()
    {
        Radius = 0,
        DistanceX = -20,
        DistanceY = 0,
        Color = Color.Black
    });
}

PanelShadowEffect

[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(PanelShadowEffect), "PanelShadowEffect")]
namespace MyApp.iOS.Renderer
{
    public class PanelShadowEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            try
            {
                var effect = (ShadowEffect)Element.Effects.FirstOrDefault(e => e is ShadowEffect);
                if (effect == null)
                {
                    return;
                }

                var control = Control;
                if (control == null)
                {
                    var renderer = Platform.GetRenderer((VisualElement)Element);
                    control = renderer.ViewController.View;
                }

                control.Layer.CornerRadius = effect.Radius;
                control.Layer.ShadowColor = effect.Color.ToCGColor();
                control.Layer.ShadowOffset = new CGSize(effect.DistanceX, effect.DistanceY);
                control.Layer.ShadowOpacity = .5f;
                control.Layer.MasksToBounds = false;


                // This doesn't work either
                //Container.Layer.CornerRadius = effect.Radius;
                //Container.Layer.ShadowColor = effect.Color.ToCGColor();
                //Container.Layer.ShadowOffset = new CGSize(effect.DistanceX, effect.DistanceY);
                //Container.Layer.ShadowOpacity = .5f;
                //Container.Layer.MasksToBounds = false;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot set property on attached control. Error: {0}", ex.Message);
            }
        }

        protected override void OnDetached()
        {
        }
    }
}
1

1 Answers

2
votes

I'm pretty sure that you're attaching the effect to a wrong control or in a wrong place. I got it to work by subscribing to the Appearing event of the NavigationPage (as seen in MainPage.xaml) and attaching the effect there.

PanelShadowEffect.cs

[assembly: ResolutionGroupName("MasterDetailPageNavigation")]
[assembly: ExportEffect(typeof(PanelShadowEffect), "PanelShadowEffect")]
namespace MasterDetailPageNavigation.iOS
{
    public class PanelShadowEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            try
            {
                var effect = (ShadowEffect)Element.Effects.FirstOrDefault(e => e is ShadowEffect);
                if (effect == null)
                {
                    return;
                }

                Container.Layer.CornerRadius = effect.Radius;
                Container.Layer.ShadowColor = effect.Color.ToCGColor();
                Container.Layer.ShadowOffset = new CGSize(effect.DistanceX, effect.DistanceY);
                Container.Layer.ShadowOpacity = .5f;
                Container.Layer.MasksToBounds = false;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot set property on attached control. Error: {0}", ex.Message);
            }
        }

        protected override void OnDetached()
        {
        }
    }
}

MainPage.xaml

<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" 
                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
                  xmlns:effects="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
                  xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
                  x:Class="MasterDetailPageNavigation.MainPage">
<MasterDetailPage.Master>
  <local:MasterPage x:Name="masterPage" />
  </MasterDetailPage.Master>
    <MasterDetailPage.Detail>
        <NavigationPage x:Name="NaviPage" Appearing="NavigationPage_Appearing">
            <x:Arguments>
                <local:ContactsPage />
            </x:Arguments>
        </NavigationPage>
    </MasterDetailPage.Detail>
</MasterDetailPage>

MainPage.xaml.cs

void NavigationPage_Appearing(object sender, System.EventArgs e)
{
    NaviPage.Effects.Add(new ShadowEffect()
    {
        Radius = 0,
        DistanceX = -20,
        DistanceY = 0,
        Color = Color.Black
    });
}

Here's the result: Drop shadow on a navigation page on iOS