Skip to content

Instantly share code, notes, and snippets.

@usausa
Last active September 27, 2020 11:01
Show Gist options
  • Save usausa/619b00b94bce0d01e8cba28e8eafa38d to your computer and use it in GitHub Desktop.
Save usausa/619b00b94bce0d01e8cba28e8eafa38d to your computer and use it in GitHub Desktop.
Xamarin.Forms custom side menu
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="SideMenuTest.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<AbsoluteLayout>
<StackLayout
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
Background="Blue">
<Label
FontSize="Large"
Text="12345678901234567890"
TextColor="White" />
</StackLayout>
<BoxView
AbsoluteLayout.LayoutBounds="0,0,AutoSize,1"
AbsoluteLayout.LayoutFlags="XProportional,YProportional,HeightProportional"
Opacity="0"
WidthRequest="16">
<BoxView.GestureRecognizers>
<PanGestureRecognizer PanUpdated="Anchor_OnPanUpdated" />
</BoxView.GestureRecognizers>
</BoxView>
<StackLayout
x:Name="SideMenu"
AbsoluteLayout.LayoutBounds="-240,0,AutoSize,1"
AbsoluteLayout.LayoutFlags="YProportional,HeightProportional"
Background="Green"
WidthRequest="240">
<StackLayout.GestureRecognizers>
<PanGestureRecognizer PanUpdated="SideMenu_OnPanUpdated" />
</StackLayout.GestureRecognizers>
</StackLayout>
</AbsoluteLayout>
</ContentPage>
namespace SideMenuTest
{
using System;
using Xamarin.Forms;
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
}
private bool showSideMenu;
private double lastPosition;
private void Anchor_OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (e.StatusType == GestureStatus.Started)
{
ViewExtensions.CancelAnimations(SideMenu);
var rect = AbsoluteLayout.GetLayoutBounds(SideMenu);
showSideMenu = rect.X > -SideMenu.Width;
lastPosition = rect.X;
}
else if (e.StatusType == GestureStatus.Running)
{
var rect = AbsoluteLayout.GetLayoutBounds(SideMenu);
rect.X = Math.Max(Math.Min(0, e.TotalX - SideMenu.Width), -SideMenu.Width);
AbsoluteLayout.SetLayoutBounds(SideMenu, rect);
if (rect.X > lastPosition)
{
showSideMenu = true;
}
else if (rect.X < lastPosition)
{
showSideMenu = false;
}
lastPosition = rect.X;
}
else if (e.StatusType == GestureStatus.Completed)
{
var rect = AbsoluteLayout.GetLayoutBounds(SideMenu);
var pos = showSideMenu ? 0 : -SideMenu.Width;
var length = (uint)(250 * Math.Abs(pos - rect.X) / SideMenu.Width);
SideMenu.Animate("Slide", x =>
{
rect.X = x;
AbsoluteLayout.SetLayoutBounds(SideMenu, rect);
}, rect.X, pos, length: length);
}
}
private void SideMenu_OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (e.StatusType == GestureStatus.Started)
{
ViewExtensions.CancelAnimations(SideMenu);
var rect = AbsoluteLayout.GetLayoutBounds(SideMenu);
showSideMenu = rect.X > -SideMenu.Width;
lastPosition = rect.X;
}
else if (e.StatusType == GestureStatus.Running)
{
var rect = AbsoluteLayout.GetLayoutBounds(SideMenu);
rect.X = Math.Max(Math.Min(0, rect.X + e.TotalX), -SideMenu.Width);
AbsoluteLayout.SetLayoutBounds(SideMenu, rect);
if (rect.X > lastPosition)
{
showSideMenu = true;
}
else if (rect.X < lastPosition)
{
showSideMenu = false;
}
lastPosition = rect.X;
}
else if (e.StatusType == GestureStatus.Completed)
{
var rect = AbsoluteLayout.GetLayoutBounds(SideMenu);
var pos = showSideMenu ? 0 : -SideMenu.Width;
var length = (uint)(250 * Math.Abs(pos - rect.X) / SideMenu.Width);
SideMenu.Animate("Slide", x =>
{
rect.X = x;
AbsoluteLayout.SetLayoutBounds(SideMenu, rect);
}, rect.X, pos, length: length);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment