Luke Vo
Luke Vo

Reputation: 20738

Add a common Element that should always be visible for Xamarin Forms Shell

I want to make a layout like this:

enter image description here

I am using Shell with Tab (no Flyout for now) and I don't know how I can achieve this. I tried creating a Page but obviously it doesn't work:

    <ContentPage.Content>
        <StackLayout>
            <root:AppShell />
            <Label Text="My Content" />
        </StackLayout>
    </ContentPage.Content>

Is there a way to wrap the content/Shell with something? Also it's preferably that that content should be above the Tabs but it's okay to be below as well.

Upvotes: 0

Views: 332

Answers (1)

Leo Zhu
Leo Zhu

Reputation: 15011

You could use Shell CustomRender to achieve this.

Create TodoTabBar in the forms project:

public class TodoTabBar : TabBar
  {
    public StackLayout BottomLayout { get; set; }
  }

then set in the AppShell.xaml:

 <c:TodoTabBar> 
    <c:TodoTabBar.BottomLayout>
      <StackLayout  HorizontalOptions="StartAndExpand" HeightRequest="200">
          <Label Text="I'm bottomview"></Label>
      </StackLayout>
    </c:TodoTabBar.BottomLayout>

    <Tab ..>
        <ShellContent ContentTemplate="..." />
    </Tab>

    <Tab ...>
        <ShellContent ContentTemplate="..." />
    </Tab>
</c:TodoTabBar>

create TodoShellRenderer and TodoShellItemRenderer in your Android project:

public class TodoShellRenderer : ShellRenderer
{
    public TodoShellRenderer(Context context) : base(context)
    {
    }

    protected override IShellItemRenderer CreateShellItemRenderer(ShellItem shellItem)
    {
        return new TodoShellItemRenderer(this);
    }
}

and

public class TodoShellItemRenderer : ShellItemRenderer
{
    FrameLayout _shellOverlay;
    BottomNavigationView _bottomView;
    public TodoShellItemRenderer(IShellContext shellContext) : base(shellContext)
    {
    }

    public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        var outerlayout = base.OnCreateView(inflater, container, savedInstanceState);
        _bottomView = outerlayout.FindViewById<BottomNavigationView>(Resource.Id.bottomtab_tabbar);
        _shellOverlay = outerlayout.FindViewById<FrameLayout>(Resource.Id.bottomtab_tabbar_container);

        if (ShellItem is TodoTabBar todoTabBar && todoTabBar.BottomLayout != null)
            SetupBottomLayout();

        return outerlayout;
    }

    private async void SetupBottomLayout()
    {
        var todoTabBar = (TodoTabBar)ShellItem;
        var layout = new FrameLayout(Context);

        var stackLayout = todoTabBar.BottomLayout;

        var size = new Rectangle(0, 0, Context.Resources.DisplayMetrics.WidthPixels, stackLayout.HeightRequest);

        var vRenderer = RendererFactory.GetRenderer(stackLayout);
        var viewGroup = vRenderer.ViewGroup;
        vRenderer.Tracker.UpdateLayout();
        var layoutParams = new ViewGroup.LayoutParams((int)size.Width, (int)size.Height);
        viewGroup.LayoutParameters = layoutParams;
        stackLayout.Layout(size);
        viewGroup.Layout(0, 0, (int)stackLayout.WidthRequest, (int)stackLayout.HeightRequest);
        layout.AddView(viewGroup);
        _shellOverlay.RemoveAllViews();
        _shellOverlay.AddView(layout);
    }
 }

the BottomTabLayout.xml (this is what we should replace the defaul xml,for this to work the IDs in the layout must match exactly what was in the Xamarin Androidn Platform layout):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">

    <LinearLayout
       android:layout_above="@id/bottomtab.tabbar.container"
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
  
    <FrameLayout
       android:id="@+id/bottomtab.navarea"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_gravity="fill"
       android:layout_weight="1" />
    
    <com.google.android.material.bottomnavigation.BottomNavigationView
       android:id="@+id/bottomtab.tabbar"
       android:theme="@style/Widget.Design.BottomNavigationView"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"/>

    </LinearLayout>

    <FrameLayout
       android:id="@+id/bottomtab.tabbar.container"
       android:background="#f00"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
     />

</RelativeLayout>

Inspired by the link from Can I add a static view above the tabbar in Xamarin Forms Shell?.

Upvotes: 0

Related Questions