private void HandleTabBarHeightChanged(object sender, int height)
        {
            if (null == base.Container ||
                !(sender is BottomNavigationView bottomNavView) ||
                !(bottomNavView.Parent is ViewGroup viewGroup) ||
                null == renderer)
            {
                return;
            }
            var layoutParams = renderer.LayoutParameters as Android.Widget.RelativeLayout.LayoutParams;
            var tabHeight    = TabEffect.GetCustomTabHeight(Element);

            if (null == layoutParams || null == tabHeight || tabHeight.Mode == TabHeightMode.Absolute)
            {
                return;
            }
            var viewHeight = 0;

            //double formHeight = 0;
            if (tabHeight.Mode == TabHeightMode.RelativeToNativeTabBar)
            {
                //formHeight = Container.Context.FromPixels(height) + tabHeight.Value;
                viewHeight = height + (int)Container.Context.ToPixels(tabHeight.Value);
            }
            else
            {
                //formHeight = Container.Context.FromPixels(height) * tabHeight.Value;
                viewHeight = (int)((double)height * Container.Context.ToPixels(tabHeight.Value));
            }
            if (viewHeight != layoutParams.Height)
            {
                layoutParams.Height       = viewHeight;
                renderer.LayoutParameters = layoutParams;
            }
        }
 public MainPage()
 {
     On <Xamarin.Forms.PlatformConfiguration.Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
     TabEffect.SetCustomTabHeight(this, new TabHeight(TabHeightMode.RelativeToNativeTabBar, 16));
     TabEffect.SetBottomContentOffset(this, 16);
     InitializeComponent();
     CurrentPage = Children[1];
     foreach (var c in Children)
     {
         c.On <iOS>().SetUseSafeArea(true);
     }
 }
        protected override void OnAttached()
        {
            var effect = Element.Effects.FirstOrDefault(x => x is SignKeys.Effects.CustomTabViewEffect);

            if (effect == null || Container == null)
            {
                return;
            }

            var containerRef = new WeakReference <ViewGroup>(Container);
            var meRef        = new WeakReference <CustomTabViewEffectImpl>(this);

            Device.InvokeOnMainThreadAsync(() =>
            {
                if (containerRef.TryGetTarget(out ViewGroup container) &&
                    meRef.TryGetTarget(out CustomTabViewEffectImpl me) &&
                    container.GetChildView <BottomNavigationView>() is BottomNavigationView bottomNavView &&
                    TabEffect.GetTabView(me.Element) is VisualElement xfView)
                {
                    bottomNavView.DisableView();

                    var renderer = (VisualElementRenderer <Xamarin.Forms.View>)Xamarin.Forms.Platform.Android.Platform.CreateRendererWithContext(xfView, container.Context);
                    Xamarin.Forms.Platform.Android.Platform.SetRenderer(xfView, renderer);
                    renderer.Elevation = bottomNavView.Elevation + 1;
                    renderer.Tracker.UpdateLayout();
                    me.renderer    = renderer;
                    var viewHeight = me.CaculateTabHeight(bottomNavView);

                    me.layoutChangeListener = new RendererLayoutChangeListener();
                    renderer.AddOnLayoutChangeListener(me.layoutChangeListener);

                    var layoutParams = new Android.Widget.RelativeLayout.LayoutParams(
                        Android.Widget.RelativeLayout.LayoutParams.MatchParent,
                        viewHeight);
                    //layoutParams.AddRule(Android.Widget.LayoutRules.AlignTop, bottomNavView.Id);
                    layoutParams.AddRule(Android.Widget.LayoutRules.AlignBottom, bottomNavView.Id);
                    var parentView = (Android.Widget.RelativeLayout)bottomNavView.Parent;
                    parentView.AddView(renderer, layoutParams);
                }
            });
        }
        int CaculateTabHeight(BottomNavigationView bottomNavView)
        {
            var xfView         = renderer.Element;
            var tabHeight      = TabEffect.GetCustomTabHeight(Element);
            int viewHeight     = 0;
            var formViewHeight = xfView.HeightRequest;

            if (null == tabHeight)
            {
                viewHeight = (int)Container.Context.ToPixels(xfView.HeightRequest);
            }
            else if (tabHeight.Mode == TabHeightMode.Absolute)
            {
                viewHeight     = (int)Container.Context.ToPixels(tabHeight.Value);
                formViewHeight = tabHeight.Value;
            }
            else if (bottomNavView != null)
            {
                if (tabHeight.Mode == TabHeightMode.RelativeToNativeTabBar)
                {
                    viewHeight     = (int)Math.Round((double)bottomNavView.Height + Container.Context.ToPixels(tabHeight.Value));
                    formViewHeight = Container.Context.FromPixels(bottomNavView.Height) + tabHeight.Value;
                }
                else
                {
                    viewHeight     = (int)Math.Round((double)bottomNavView.Height * tabHeight.Value);
                    formViewHeight = Container.Context.FromPixels((double)bottomNavView.Height * tabHeight.Value);
                }
                tabBarLayoutChangeListener = new TabBarLayoutChangeListener();
                tabBarLayoutChangeListener.HeightChanged += HandleTabBarHeightChanged;
                bottomNavView.AddOnLayoutChangeListener(tabBarLayoutChangeListener);
            }
            if (bottomNavView != null)
            {
                renderer.Layout(0, 0, bottomNavView.Width, viewHeight);
                xfView.Layout(new Rectangle(0, 0, Container.Context.FromPixels(bottomNavView.Width), formViewHeight));
            }
            return(viewHeight);
        }
        protected override void OnAttached()
        {
            var effect = Element.Effects.FirstOrDefault(x => x is SignKeys.Effects.CustomTabViewEffect);

            if (effect == null || Container == null)
            {
                return;
            }

            var containerRef = new WeakReference <UIView>(Container);
            var meRef        = new WeakReference <CustomTabViewEffectImpl>(this);

            Device.InvokeOnMainThreadAsync(() =>
            {
                if (containerRef.TryGetTarget(out UIView container) &&
                    meRef.TryGetTarget(out CustomTabViewEffectImpl me))
                {
                    if (!(TabEffect.GetTabView(me.Element) is VisualElement xfView))
                    {
                        return;
                    }
                    me.rendererContainer = new RendererContainer(xfView);
                    container.AddSubview(me.rendererContainer);
                    me.rendererContainer.LeadingAnchor.ConstraintEqualTo(container.LeadingAnchor).Active   = true;
                    me.rendererContainer.TrailingAnchor.ConstraintEqualTo(container.TrailingAnchor).Active = true;
                    me.rendererContainer.BottomAnchor.ConstraintEqualTo(container.BottomAnchor).Active     = true;
                    //me.rendererContainer.HeightAnchor.ConstraintEqualTo((nfloat)xfView.HeightRequest + container.SafeAreaInsets.Bottom).Active = true;
                    var heightConfig = TabEffect.GetCustomTabHeight(me.Element);
                    var tabBar       = me.Container.Subviews?.FirstOrDefault((v) => v is UITabBar) as UITabBar;
                    if (null != tabBar)
                    {
                        // Remove bar's shadow & top line
                        me.originalBackgroundImage = tabBar.BackgroundImage;
                        tabBar.BackgroundImage     = new UIImage();
                        me.originalShadowImage     = tabBar.ShadowImage;
                        tabBar.ShadowImage         = new UIImage();
                        tabBar.ClipsToBounds       = true;
                    }
                    if (heightConfig == null)
                    {
                        var constraint = me.rendererContainer.TopAnchor.ConstraintEqualTo(container.LayoutMarginsGuide.BottomAnchor, -(nfloat)xfView.HeightRequest);
                        constraint.SetIdentifier("top_to_bottom");
                        constraint.Active = true;
                    }
                    else
                    {
                        if (heightConfig.Mode == TabHeightMode.Absolute)
                        {
                            var constraint = me.rendererContainer.TopAnchor.ConstraintEqualTo(container.LayoutMarginsGuide.BottomAnchor, -(nfloat)heightConfig.Value);
                            constraint.SetIdentifier("top_to_bottom");
                            constraint.Active = true;
                        }
                        else if (null != tabBar)
                        {
                            if (heightConfig.Mode == TabHeightMode.RelativeToNativeTabBar)
                            {
                                var constraint = me.rendererContainer.HeightAnchor.ConstraintEqualTo(tabBar.HeightAnchor, 1.0f, (nfloat)heightConfig.Value);
                                constraint.SetIdentifier("relative_height");
                                constraint.Active = true;
                            }
                            else
                            {
                                var constraint = me.rendererContainer.HeightAnchor.ConstraintEqualTo(tabBar.HeightAnchor, (nfloat)heightConfig.Value, 0.0f);
                                constraint.SetIdentifier("proportional_height");
                                constraint.Active = true;
                            }
                        }
                    }
                    me.rendererContainer.UpdateBackgroundColor(TabEffect.GetTabBarColor(me.Element).ToUIColor());
                }
            });
        }
        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(args);
            if (null == rendererContainer || null == Element || null == Container)
            {
                return;
            }
            if (args.PropertyName == VisualElement.HeightProperty.PropertyName)
            {
                var heightConfig = TabEffect.GetCustomTabHeight(Element);
                if (null == heightConfig)
                {
                    var contraints = rendererContainer.Constraints;
                    if (contraints.FirstOrDefault((c) => string.Equals(c.GetIdentifier(), "top_to_bottom")) is NSLayoutConstraint constraint)
                    {
                        constraint.Constant = -(nfloat)((VisualElement)Element).HeightRequest;
                        rendererContainer.UpdateConstraints();
                    }
                }
            }
            if (args.PropertyName == TabEffect.TabBarColorProperty.PropertyName)
            {
                rendererContainer.UpdateBackgroundColor(TabEffect.GetTabBarColor(Element).ToUIColor());
            }
            else if (args.PropertyName == TabEffect.CustomTabHeightProperty.PropertyName)
            {
                var heightConfig = TabEffect.GetCustomTabHeight(Element);
                var contraints   = rendererContainer.Constraints;
                if (null == heightConfig || heightConfig.Mode == TabHeightMode.Absolute)
                {
                    var value      = -(nfloat)(null == heightConfig ? (rendererContainer.FormsView?.HeightRequest ?? 0) : heightConfig.Value);
                    var found      = false;
                    var shouldStop = false;
                    foreach (var c in contraints)
                    {
                        var id = c.GetIdentifier();
                        switch (id)
                        {
                        case "top_to_bottom":
                            c.Constant = value;
                            found      = true;
                            break;

                        case "relative_height":
                        case "proportional_height":
                            rendererContainer.RemoveConstraint(c);
                            shouldStop = true;
                            break;

                        default: break;
                        }
                        if (found || shouldStop)
                        {
                            break;
                        }
                    }
                    if (false == found)
                    {
                        var constraint = rendererContainer.TopAnchor.ConstraintEqualTo(Container.LayoutMarginsGuide.BottomAnchor, value);
                        constraint.SetIdentifier("top_to_bottom");
                        constraint.Active = true;
                    }
                }
                else
                {
                    var value             = (nfloat)heightConfig.Value;
                    var shouldStop        = false;
                    var needNewConstraint = true;
                    foreach (var c in contraints)
                    {
                        var id = c.GetIdentifier();
                        switch (id)
                        {
                        case "top_to_bottom":
                        case "proportional_height":
                            rendererContainer.RemoveConstraint(c);
                            shouldStop = true;
                            break;

                        case "relative_height":
                            if (heightConfig.Mode == TabHeightMode.RelativeToNativeTabBar)
                            {
                                c.Constant        = value;
                                needNewConstraint = false;
                            }
                            else
                            {
                                rendererContainer.RemoveConstraint(c);
                                shouldStop = true;
                            }
                            break;

                        default: break;
                        }
                        if (!needNewConstraint || shouldStop)
                        {
                            break;
                        }
                    }
                    if (needNewConstraint && Container.Subviews?.FirstOrDefault((v) => v is UITabBar) is UITabBar tabBar)
                    {
                        if (heightConfig.Mode == TabHeightMode.RelativeToNativeTabBar)
                        {
                            var constraint = rendererContainer.HeightAnchor.ConstraintEqualTo(tabBar.HeightAnchor, 1.0f, value);
                            constraint.SetIdentifier("relative_height");
                            constraint.Active = true;
                        }
                        else
                        {
                            var constraint = rendererContainer.HeightAnchor.ConstraintEqualTo(tabBar.HeightAnchor, value, 0.0f);
                            constraint.SetIdentifier("proportional_height");
                            constraint.Active = true;
                        }
                    }
                }
            }
        }