2021-08-10 17:17:32 +08:00

149 lines
4.0 KiB
C#

using System;
using Gallery.Services;
using Gallery.Util;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Gallery.Resources.UI
{
public class AdaptedPage : ContentPage
{
public static readonly BindableProperty TopMarginProperty = BindableProperty.Create(nameof(TopMargin), typeof(Thickness), typeof(AdaptedPage));
public Thickness TopMargin
{
get => (Thickness)GetValue(TopMarginProperty);
set => SetValue(TopMarginProperty, value);
}
public event EventHandler Load;
public event EventHandler Unload;
protected static readonly bool isPhone = DeviceInfo.Idiom == DeviceIdiom.Phone;
public AdaptedPage()
{
SetDynamicResource(Screen.StatusBarStyleProperty, Theme.Theme.StatusBarStyle);
Shell.SetNavBarHasShadow(this, true);
}
public virtual void OnLoad() => Load?.Invoke(this, EventArgs.Empty);
public virtual void OnUnload() => Unload?.Invoke(this, EventArgs.Empty);
public virtual void OnOrientationChanged(bool landscape)
{
var old = TopMargin;
Thickness @new;
if (Definition.IsFullscreenDevice)
{
@new = landscape ?
AppShell.NavigationBarOffset :
AppShell.TotalBarOffset;
}
else if (isPhone)
{
@new = landscape ?
Definition.TopOffset32 :
AppShell.TotalBarOffset;
}
else
{
// iPad
@new = AppShell.TotalBarOffset;
}
if (old != @new)
{
TopMargin = @new;
OnTopMarginChanged(old, @new);
}
}
protected virtual void OnTopMarginChanged(Thickness old, Thickness @new) { }
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
OnOrientationChanged(width > height);
}
protected void AnimateToMargin(View element, Thickness margin, bool animate = true)
{
var m = margin;
var start = element.Margin.Top - m.Top;
element.Margin = m;
element.CancelAnimations();
if (start > 0 && animate)
{
element.Animate("margin", top =>
{
element.TranslationY = top;
},
start, 0,
#if DEBUG
length: 500,
#else
length: 300,
#endif
easing: Easing.SinInOut,
finished: (v, r) =>
{
element.TranslationY = 0;
});
}
else if (element.TranslationY != 0)
{
element.TranslationY = 0;
}
}
protected void Start(Action action)
{
if (Tap.IsBusy)
{
Log.Error($"{GetType()}.tap", "gesture recognizer is now busy...");
return;
}
using (Tap.Start())
{
action();
}
}
private class Tap : IDisposable
{
public static bool IsBusy
{
get
{
lock (sync)
{
return instance?.isBusy == true;
}
}
}
private static readonly object sync = new();
private static readonly Tap instance = new();
private Tap() { }
public static Tap Start()
{
lock (sync)
{
instance.isBusy = true;
}
return instance;
}
private bool isBusy = false;
public void Dispose()
{
isBusy = false;
}
}
}
}