Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin.Forms Navigation.PushAsync as Side Menu

I am using Xamarin.Forms and I have 2 pages, one is a List View, the other is a just a view I am using as a filter for the List View. I am currently using Navigation.PushAsync to display this page, my question is, is there away to present it like a side menu? I know there is Master Detail View which I am already using for the main menu and I dont think I can have 2 Master Details in my app, I tried that approach but it adds an additional navigation.

Here is my code.

public partial class PatientsPage : ContentPage
    {

        public PatientsPage()
        {
            InitializeComponent();

            ToolbarItems.Add(new ToolbarItem("Filter", "filter.png", () => { openFilter(); }));

        }

        public async void openFilter()
        {
            await Navigation.PushAsync(new PatientFiltersPage());
        }
    }

UPDATE

Is there away to have 2 details in 1 master to accomplish this? I really don't want to use a 3rd party library.

like image 284
user979331 Avatar asked Oct 29 '20 21:10

user979331


1 Answers

I personally do not know of

any way to have 2 details in 1 master

According to the documentation:

The Xamarin.Forms MasterDetailPage is a page that manages two related pages of information – a master page that presents items, and a detail page that presents details about items on the master page.

So in theory only one Detail page is allowed per Master page (although the detail page can be a NavigationPage itself).

But if you are flexible about how to approach your problem, i would suggest using an overlay with AbsoluteLayout.

As an example, look at the image below, where i have a view over the main CollectionView that can be shown or hidden by tapping on the "Filter" button:

enter image description here

Of course you can get as creative as you want, and make the view appear sliding from below, or from the side, or fading in: there is a robust support for animations in Xamarin.Forms. Also the view can be scrollable so that if you have a variety of filters you do not cover the whole CollectionView with the Filter.

If that kind of solution is tolerable, you can achieve it as follows:

XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FilterDetail.StartPage">

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Filter"
                     Clicked="ToolbarItem_Clicked"/>
    </ContentPage.ToolbarItems>
    
    <ContentPage.Content>
        <AbsoluteLayout>
            <CollectionView x:Name="listView" AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <StackLayout>
                            <Frame Margin="15">
                                <Label Text="{Binding .}"/>
                            </Frame>
                            
                        </StackLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>

            <ContentView x:Name="FilterOverlay"
                     IsVisible="True" VerticalOptions="End"
                     AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All"
                     BackgroundColor="Transparent">
                <Frame CornerRadius="10"
                   Margin="10"
                   HorizontalOptions="FillAndExpand" InputTransparent="False">
                    <StackLayout Padding="0">
                        <Label x:Name="FilterText"
                               Text="Filter Options"
                           FontSize="Medium"
                           TextColor="Black"/>

                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 1"/>
                            <Switch IsToggled="True" />
                            
                        </StackLayout>

                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 2"/>
                            <Switch IsToggled="True" />

                        </StackLayout>


                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 3"/>
                            <Switch IsToggled="False" />

                        </StackLayout>
                        
                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 4"/>
                            <Switch IsToggled="True" />

                        </StackLayout>
                        
                        <Button Text="Apply"
                                HeightRequest="30"
                                Padding="0"
                               BackgroundColor="Accent"/>
                    </StackLayout>
                </Frame>
            </ContentView>
        </AbsoluteLayout>
        
    </ContentPage.Content>
</ContentPage>

Code behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace FilterDetail
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class StartPage : ContentPage
    {
        public StartPage()
        {
            InitializeComponent();

            var items = new List<String>();
            for (int i = 0; i < 1000; i++)
                items.Add($"Item {i}");

            listView.SetBinding(CollectionView.ItemsSourceProperty, new Binding() { Source = items, Path = "." });

        }

        private void ToolbarItem_Clicked(object sender, EventArgs e)
        {
            FilterOverlay.IsVisible = !FilterOverlay.IsVisible;
        }
    }
}

Update

In order to simulate a second Master/Menu we can simply modify our solution presented above in order to expand our overlay vertically and add some animation so that instead of simply appear and disappear, the overlay hides to the right.

Let's see how this is done:

The Overlay

Add an overlay that covers the whole screen except from a margin on the left so that it looks like a Master Menu.

Xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FilterDetail.StartPage">

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Filter"
                     Clicked="ToolbarItem_Clicked"/>
    </ContentPage.ToolbarItems>
    
    <ContentPage.Content>
        <AbsoluteLayout>
            <CollectionView x:Name="listView" AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <StackLayout>
                            <Frame Margin="15">
                                <Label Text="{Binding .}"/>
                            </Frame>
                            
                        </StackLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>

            <ContentView x:Name="FilterOverlay"
                     IsVisible="True"
                     AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All"
                     BackgroundColor="Transparent">
                <Frame CornerRadius="10"
                       Margin="100,10,0,10"
                       HorizontalOptions="FillAndExpand"
                       VerticalOptions="FillAndExpand"
                       InputTransparent="False">
                    <StackLayout Padding="0">
                        <Label x:Name="FilterText"
                               Text="Filter Options"
                           FontSize="Medium"
                           TextColor="Black"/>

                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 1"/>
                            <Switch IsToggled="True" />
                            
                        </StackLayout>

                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 2"/>
                            <Switch IsToggled="True" />

                        </StackLayout>


                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 3"/>
                            <Switch IsToggled="False" />

                        </StackLayout>
                        
                        <StackLayout Orientation="Horizontal"
                                 HorizontalOptions="CenterAndExpand">
                            <Label Text="Filter key 4"/>
                            <Switch IsToggled="True" />

                        </StackLayout>
                        
                        <Button Text="Apply"
                                HeightRequest="30"
                                Padding="0"
                               BackgroundColor="Accent"
                                VerticalOptions="EndAndExpand"/>
                    </StackLayout>
                </Frame>
            </ContentView>
        </AbsoluteLayout>
        
    </ContentPage.Content>
</ContentPage>

Next, add some animation to ToolbarItem_Clicked so that on tapping the Filter toolbar item, the overlay hides to the right

Code Behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace FilterDetail
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class StartPage : ContentPage
    {
        public StartPage()
        {
            InitializeComponent();

            var items = new List<String>();
            for (int i = 0; i < 1000; i++)
                items.Add($"Item {i}");

            listView.SetBinding(CollectionView.ItemsSourceProperty, new Binding() { Source = items, Path = "." });

        }

        private async void ToolbarItem_Clicked(object sender, EventArgs e)
        {
            if (FilterOverlay.IsVisible)
            {
                // If overlay is visible, slide it to the right, and set as invisible.
                await FilterOverlay.TranslateTo(this.Width-100, FilterOverlay.Y);
                FilterOverlay.IsVisible = false;
            }
            else
            {
                // If overlay is invisible, make it visible and slide to the left.
                FilterOverlay.IsVisible = true;
                await FilterOverlay.TranslateTo(0, FilterOverlay.Y);
            }
        }
    }
}

And that's it. The result looks like this:

enter image description here

Of course this is only a sample, and a bit of extra work on the overlay and on the animation can give you amazing results. Enjoy!

like image 167
deczaloth Avatar answered Nov 08 '22 02:11

deczaloth