maui-linux/Xamarin.Forms.Platform.MacOS/ModalPageTracker.cs

131 строка
3.5 KiB
C#

using System;
using System.Threading.Tasks;
using System.Linq;
using AppKit;
using System.Collections.Generic;
namespace Xamarin.Forms.Platform.MacOS
{
internal class ModalPageTracker : IDisposable
{
NSViewController _renderer;
List<Page> _modals;
bool _disposed;
public ModalPageTracker(NSViewController mainRenderer)
{
if (mainRenderer == null)
throw new ArgumentNullException(nameof(mainRenderer));
_renderer = mainRenderer;
_renderer.View.WantsLayer = true;
_modals = new List<Page>();
}
public List<Page> ModalStack => _modals;
public Task PushAsync(Page modal, bool animated)
{
_modals.Add(modal);
modal.DescendantRemoved += HandleChildRemoved;
Platform.NativeToolbarTracker.TryHide(modal as NavigationPage);
return PresentModalAsync(modal, animated);
}
public Task<Page> PopAsync(bool animated)
{
var modal = _modals.LastOrDefault();
if (modal == null)
throw new InvalidOperationException("No Modal pages found in the stack, make sure you pushed a modal page");
_modals.Remove(modal);
modal.DescendantRemoved -= HandleChildRemoved;
return HideModalAsync(modal, animated);
}
internal void LayoutSubviews()
{
if (_renderer == null || _renderer.View == null)
return;
foreach(var modal in _modals)
{
var modalRenderer = Platform.GetRenderer(modal);
if(modalRenderer != null)
modalRenderer.SetElementSize(new Size(_renderer.View.Bounds.Width, _renderer.View.Bounds.Height));
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
foreach (var modal in _modals)
Platform.DisposeModelAndChildrenRenderers(modal);
_renderer = null;
}
_disposed = true;
}
}
void HandleChildRemoved(object sender, ElementEventArgs e)
{
var view = e.Element;
Platform.DisposeModelAndChildrenRenderers(view);
}
Task PresentModalAsync(Page modal, bool animated)
{
var modalRenderer = Platform.GetRenderer(modal);
if (modalRenderer == null)
{
modalRenderer = Platform.CreateRenderer(modal);
Platform.SetRenderer(modal, modalRenderer);
modalRenderer.SetElementSize(new Size(_renderer.View.Bounds.Width, _renderer.View.Bounds.Height));
}
var toViewController = modalRenderer as NSViewController;
var i = Math.Max(0, _renderer.ChildViewControllers.Length - 1);
var fromViewController = _renderer.ChildViewControllers[i];
_renderer.AddChildViewController(toViewController);
NSViewControllerTransitionOptions option = animated
? NSViewControllerTransitionOptions.SlideUp
: NSViewControllerTransitionOptions.None;
var task = _renderer.HandleAsyncAnimation(fromViewController, toViewController, option,
() =>
{
//Hack: adjust if needed
toViewController.View.Frame = _renderer.View.Bounds;
fromViewController.View.Layer.Hidden = true;
}, true);
return task;
}
Task<Page> HideModalAsync(Page modal, bool animated)
{
var controller = Platform.GetRenderer(modal) as NSViewController;
var i = Math.Max(0, _renderer.ChildViewControllers.Length - 2);
var toViewController = _renderer.ChildViewControllers[i];
toViewController.View.Layer.Hidden = false;
NSViewControllerTransitionOptions option = animated
? NSViewControllerTransitionOptions.SlideDown
: NSViewControllerTransitionOptions.None;
var task = _renderer.HandleAsyncAnimation(controller, toViewController, option,
() => Platform.DisposeModelAndChildrenRenderers(modal), modal);
return task;
}
}
}