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; } } } } }