mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-28 23:08:36 +08:00
Refactor DrawerLayer
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace AtomUI.Controls;
|
||||
|
||||
internal class DrawerLayer : Canvas
|
||||
public class DrawerLayer : Canvas
|
||||
{
|
||||
private const int DrawerLayerZIndex = int.MaxValue - 1000;
|
||||
|
||||
@@ -22,6 +26,15 @@ internal class DrawerLayer : Canvas
|
||||
|
||||
public static readonly AttachedProperty<Control?> DrawerContainerProperty =
|
||||
AvaloniaProperty.RegisterAttached<DrawerLayer, Visual, Control?>("DrawerContainer");
|
||||
|
||||
public static readonly StyledProperty<Visual?> LayerHostProperty = AvaloniaProperty
|
||||
.Register<DrawerLayer, Visual?>(nameof(LayerHost));
|
||||
|
||||
public Visual? LayerHost
|
||||
{
|
||||
get => GetValue(LayerHostProperty);
|
||||
set => SetValue(LayerHostProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -50,26 +63,49 @@ internal class DrawerLayer : Canvas
|
||||
Children.CollectionChanged += ChildrenCollectionChanged;
|
||||
}
|
||||
|
||||
public static Visual? GetAttachTargetElement(Visual drawerContainer)
|
||||
public static Visual? GetAttachTargetElement(Visual control)
|
||||
{
|
||||
return drawerContainer.GetValue(AttachTargetElementProperty);
|
||||
return control.GetValue(AttachTargetElementProperty);
|
||||
}
|
||||
|
||||
public static void SetAttachTargetElement(Visual drawerContainer, Visual? attachTarget)
|
||||
public static void SetAttachTargetElement(Visual control, Visual? attachTarget)
|
||||
{
|
||||
drawerContainer.SetValue(AttachTargetElementProperty, attachTarget);
|
||||
control.SetValue(AttachTargetElementProperty, attachTarget);
|
||||
}
|
||||
|
||||
public static DrawerLayer GetDrawerLayer(Visual visual)
|
||||
public static DrawerLayer? GetDrawerLayer(Visual visual)
|
||||
{
|
||||
var layer = visual.FindAncestorOfType<VisualLayerManager>()?.GetVisualChildren()
|
||||
.FirstOrDefault(c => c is DrawerLayer) as DrawerLayer;
|
||||
if (layer == null)
|
||||
Layoutable? layerHost = visual.FindAncestorOfType<ScrollContentPresenter>(true);
|
||||
var attachTarget = GetAttachTargetElement(visual);
|
||||
if (layerHost != null && attachTarget != null)
|
||||
{
|
||||
layer = new DrawerLayer();
|
||||
AddLayerToVisualLayerManager(visual, layer, DrawerLayerZIndex);
|
||||
while (layerHost != null && layerHost.IsVisualAncestorOf(attachTarget) == false)
|
||||
{
|
||||
layerHost = layerHost.FindAncestorOfType<ScrollContentPresenter>();
|
||||
}
|
||||
}
|
||||
|
||||
if (layerHost is ScrollContentPresenter scrollContentPresenter)
|
||||
{
|
||||
scrollContentPresenter.PropertyChanged += (sender, args) =>
|
||||
{
|
||||
if (args.Property == ScrollContentPresenter.OffsetProperty)
|
||||
{
|
||||
Console.WriteLine($"{attachTarget?.TranslatePoint(new Point(0, 0), TopLevel.GetTopLevel(visual)!)}");
|
||||
}
|
||||
};
|
||||
}
|
||||
layerHost ??= visual.FindAncestorOfType<VisualLayerManager>();
|
||||
layerHost ??= TopLevel.GetTopLevel(visual);
|
||||
|
||||
if (layerHost == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var layer = layerHost.GetVisualChildren().FirstOrDefault(c => c is DrawerLayer) as DrawerLayer;
|
||||
layer ??= InjectLayer(layerHost);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
@@ -180,9 +216,8 @@ internal class DrawerLayer : Canvas
|
||||
}
|
||||
info.Subscription = attachTarget.GetObservable(BoundsProperty).Subscribe(x =>
|
||||
{
|
||||
var attachTargetToplevel = TopLevel.GetTopLevel(attachTarget);
|
||||
var translationMatrix = attachTargetToplevel != null
|
||||
? attachTarget.TransformToVisual(attachTargetToplevel) ?? Matrix.Identity
|
||||
var translationMatrix = LayerHost != null
|
||||
? attachTarget.TransformToVisual(LayerHost) ?? Matrix.Identity
|
||||
: Matrix.Identity;
|
||||
info.Bounds = new TransformedBounds(new Rect(attachTarget.DesiredSize), new Rect(attachTarget.DesiredSize),
|
||||
translationMatrix);
|
||||
@@ -317,6 +352,70 @@ internal class DrawerLayer : Canvas
|
||||
AddLayerMethodInfo.Invoke(visualLayerManager, [layer, zindex]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddLayerToVisualLayerManager(VisualLayerManager visualLayerManager, Control layer, int zindex)
|
||||
{
|
||||
AddLayerMethodInfo.Invoke(visualLayerManager, [layer, zindex]);
|
||||
}
|
||||
|
||||
private static DrawerLayer InjectLayer(Layoutable layerHost)
|
||||
{
|
||||
var drawerLayer = layerHost.FindDescendantOfType<DrawerLayer>();
|
||||
if (drawerLayer != null)
|
||||
{
|
||||
return drawerLayer;
|
||||
}
|
||||
|
||||
drawerLayer = new DrawerLayer
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
ZIndex = DrawerLayerZIndex
|
||||
};
|
||||
|
||||
drawerLayer.LayerHost = layerHost;
|
||||
if (layerHost is VisualLayerManager visualLayerManager)
|
||||
{
|
||||
AddLayerToVisualLayerManager(visualLayerManager, drawerLayer, visualLayerManager.ZIndex);
|
||||
}
|
||||
else if (layerHost is ScrollContentPresenter scrollContentPresenter)
|
||||
{
|
||||
if (scrollContentPresenter.Content is Control controlContent)
|
||||
{
|
||||
// 直接内容控件
|
||||
scrollContentPresenter.Content = null;
|
||||
scrollContentPresenter.UpdateChild();
|
||||
var panel = new Panel
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
};
|
||||
panel.Children.Add(controlContent);
|
||||
panel.Children.Add(drawerLayer);
|
||||
scrollContentPresenter.Content = panel;
|
||||
}
|
||||
else if (scrollContentPresenter.Content != null && scrollContentPresenter.ContentTemplate != null)
|
||||
{
|
||||
// 模版处理
|
||||
var injectTemplate = new FuncDataTemplate<object?>((o, scope) =>
|
||||
{
|
||||
var originControl = scrollContentPresenter.ContentTemplate.Build(o);
|
||||
var panel = new Panel
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
};
|
||||
Debug.Assert(originControl != null);
|
||||
panel.Children.Add(originControl);
|
||||
panel.Children.Add(drawerLayer);
|
||||
return panel;
|
||||
});
|
||||
scrollContentPresenter.ContentTemplate = injectTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
return drawerLayer;
|
||||
}
|
||||
|
||||
private class AttachTargetElementInfo
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using AtomUI.Controls.Primitives;
|
||||
using AtomUI.Data;
|
||||
using AtomUI.Theme;
|
||||
using AtomUI.Theme.Utils;
|
||||
@@ -250,9 +249,19 @@ public class DrawerX : Control,
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
if (change.Property == IsOpenProperty)
|
||||
if (VisualRoot != null)
|
||||
{
|
||||
HandleIsOpenChanged();
|
||||
if (change.Property == IsOpenProperty)
|
||||
{
|
||||
HandleIsOpenChanged();
|
||||
}
|
||||
}
|
||||
if (change.Property == OpenOnProperty)
|
||||
{
|
||||
if (OpenOn != null)
|
||||
{
|
||||
DrawerLayer.SetAttachTargetElement(this, OpenOn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,9 +279,10 @@ public class DrawerX : Control,
|
||||
|
||||
private void Open()
|
||||
{
|
||||
CreateDrawerContainer();
|
||||
var layer = DrawerLayer.GetDrawerLayer(this);
|
||||
Debug.Assert(layer != null);
|
||||
NotifyBeforeOpen(layer);
|
||||
CreateDrawerContainer();
|
||||
Debug.Assert(_container != null);
|
||||
_container.Open(layer);
|
||||
}
|
||||
@@ -281,13 +291,13 @@ public class DrawerX : Control,
|
||||
{
|
||||
var layer = DrawerLayer.GetDrawerLayer(this);
|
||||
Debug.Assert(layer != null);
|
||||
NotifyBeforeClose(layer);
|
||||
Debug.Assert(_container != null);
|
||||
_container.Close(layer);
|
||||
}
|
||||
|
||||
private void CreateDrawerContainer()
|
||||
{
|
||||
|
||||
if (_container is null)
|
||||
{
|
||||
_container = new DrawerContainerX()
|
||||
@@ -308,6 +318,37 @@ public class DrawerX : Control,
|
||||
BindUtils.RelayBind(this, CloseWhenClickOnMaskProperty, _container, DrawerContainerX.CloseWhenClickOnMaskProperty);
|
||||
}
|
||||
}
|
||||
|
||||
protected internal virtual void NotifyBeforeOpen(DrawerLayer layer)
|
||||
{
|
||||
var current = Parent;
|
||||
while (current != null && current.GetType() != typeof(DrawerLayer))
|
||||
{
|
||||
if (current is DrawerContainerX container)
|
||||
{
|
||||
if (container.Drawer != null && container.Drawer.TryGetTarget(out var drawer))
|
||||
{
|
||||
drawer.NotifyChildDrawerAboutToOpen(this);
|
||||
}
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
internal void NotifyChildDrawerAboutToOpen(DrawerX childDrawer)
|
||||
{
|
||||
Console.WriteLine(childDrawer);
|
||||
if (_container != null)
|
||||
{
|
||||
_container.Background = Brushes.Brown;
|
||||
}
|
||||
}
|
||||
|
||||
protected internal virtual void NotifyBeforeClose(DrawerLayer layer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected internal virtual void NotifyOpened()
|
||||
{
|
||||
|
||||
@@ -36,21 +36,21 @@ internal static class UIStructureUtils
|
||||
((ISetLogicalParent)control).SetParent(parent);
|
||||
}
|
||||
|
||||
public static void ClearVisualParentRecursive(Visual control, Control? parent)
|
||||
public static void ClearVisualParentRecursive(Visual control)
|
||||
{
|
||||
SetVisualParent(control, null);
|
||||
foreach (var child in control.GetVisualChildren())
|
||||
{
|
||||
ClearVisualParentRecursive(child, parent);
|
||||
ClearVisualParentRecursive(child);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearLogicalParentRecursive(ILogical control, Control? parent)
|
||||
public static void ClearLogicalParentRecursive(ILogical control)
|
||||
{
|
||||
((ISetLogicalParent)control).SetParent(parent);
|
||||
((ISetLogicalParent)control).SetParent(null);
|
||||
foreach (var child in control.GetLogicalChildren())
|
||||
{
|
||||
ClearLogicalParentRecursive(child, parent);
|
||||
ClearLogicalParentRecursive(child);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user