Reputation: 11
In my Xamarin.Forms application I need to add a bottom bar that will be visible over the tab bar. Since my app is a Shell application, I'm trying to create a custom ShellItemRenderer.
I extended the TabBar so I that could add custom view:
<local:CustomTabBar IsBottomBarVisible="False">
<local:CustomTabBar.BottomLayout>
<StackLayout>
<Label Text="Bottom bar" />
</StackLayout>
</local:CustomTabBar.BottomLayout>
<ShellContent Title="About" Icon="icon_about.png" Route="AboutPage" ContentTemplate="{views:AppDataTemplate views:AboutPage}" />
<ShellContent Title="Browse" Icon="icon_feed.png" ContentTemplate="{views:AppDataTemplate views:ItemsPage}" />
</local:CustomTabBar>
It worked on the Android platform after extending ShellItemRenderer and implementing custom Layout, but I hit the wall on the iOS. If I have any scrollable content (ScrollView or CollectionView), my bottom bar covers some of the items: bottom bar visible, without bottom bar.
Is there a way to implement a custom layout, like on the Android platform, or to adjust existing content each time after the bottom bar appears or disappears?
Here is the implementation of CustomShellItemRenderer:
public class CustomShellItemRenderer : ShellItemRenderer
{
#region Fields
private UIView BottomBar;
#endregion Fields
#region Constructors
public CustomShellItemRenderer(IShellContext context) : base(context)
{
}
#endregion Constructors
protected CustomTabBar CustomTabBar => ShellItem as CustomTabBar;
#region Methods
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
var view = ConvertFormsToNative(CustomTabBar.BottomLayout, BottomBar.Frame);
BottomBar.AddSubview(view);
BottomBar.BackgroundColor = UIColor.Gray;
if (!CustomTabBar.IsBottomBarVisible)
{
BottomBar.Hidden = true;
}
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
TabBar.Translucent = false;
BottomBar = new UIView();
InitView();
}
private UIView ConvertFormsToNative(Xamarin.Forms.View view, CGRect size)
{
var renderer = Platform.CreateRenderer(view);
renderer.NativeView.AutoresizingMask = UIViewAutoresizing.All;
renderer.NativeView.ContentMode = UIViewContentMode.ScaleToFill;
renderer.Element.Layout(size.ToRectangle());
var nativeView = renderer.NativeView;
nativeView.SetNeedsLayout();
return nativeView;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(CustomTabBar.IsBottomBarVisible))
{
if (CustomTabBar != null)
{
if (CustomTabBar.IsBottomBarVisible)
{
BottomBar.Hidden = false;
}
else
{
BottomBar.Hidden = true;
}
}
}
}
private void InitView()
{
var window = (UIApplication.SharedApplication.Delegate as AppDelegate)?.Window;
var root = window.RootViewController;
const int height = 60;
var realTabBarHeight = TabBar.Frame.Size.Height + (UIApplication.SharedApplication.KeyWindow?.SafeAreaInsets.Bottom ?? 34);
var frame = new CGRect(TabBar.Frame.X, window.Frame.GetMaxY() - (realTabBarHeight + height), TabBar.Frame.Width, height);
BottomBar.Frame = frame;
var windowHeight = window.Frame.GetMaxY();
window.AddSubview(BottomBar);
}
#endregion Methods
}
Upvotes: 1
Views: 584
Reputation: 14475
We can adjust the height of the content dynamically while the bottom bar appears/disappears.
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(CustomTabBar.IsBottomBarVisible))
{
if (CustomTabBar != null)
{
var window = (UIApplication.SharedApplication.Delegate as AppDelegate)?.Window;
var root = window.RootViewController;
var view = root.View;
var viewframe = view.Frame;
if (CustomTabBar.IsBottomBarVisible)
{
BottomBar.Hidden = false;
viewframe.Height = viewframe.Height - bottomBarHeight;
}
else
{
BottomBar.Hidden = true;
viewframe.Height = viewframe.Height + bottomBarHeight;
}
view.Frame = viewframe;
}
}
}
Upvotes: 0