From 0e548c2d6ce09fe0add8df6932a0d83a0e22c61b Mon Sep 17 00:00:00 2001 From: Jon Lipsky Date: Tue, 9 Jul 2019 23:17:28 -0700 Subject: [PATCH] =?UTF-8?q?Added=20support=20to=20the=20iOS=20layout=20han?= =?UTF-8?q?dlers=20to=20support=20when=20a=20handler=E2=80=99s=20native=20?= =?UTF-8?q?view=20changes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HotUI.Forms.Sample.Android.csproj | 4 +- .../HotUI.Forms.Sample.iOS.csproj | 4 +- .../HotUI.Forms.Sample.csproj | 4 +- .../HotUI.Android.Sample.csproj | 2 +- sample/HotUI.Samples/MainPage.cs | 2 +- .../HotUI.iOS.Sample/HotUI.iOS.Sample.csproj | 4 +- src/HotUI.Android/HotUI.Android.csproj | 2 +- src/HotUI.Forms/HotUI.Forms.csproj | 2 +- src/HotUI.iOS/Controls/HUIContainerView.cs | 3 + src/HotUI.iOS/Handlers/AbstractHandler.cs | 14 ++- .../Handlers/AbstractLayoutHandler.cs | 106 +++++++++++++++--- src/HotUI.iOS/Handlers/ContentViewHandler.cs | 5 +- src/HotUI.iOS/Handlers/ListViewHandler.cs | 3 + src/HotUI.iOS/Handlers/ScrollViewHandler.cs | 3 + src/HotUI.iOS/Handlers/SpacerHandler.cs | 6 +- src/HotUI.iOS/Handlers/ViewHandler.cs | 11 +- src/HotUI.iOS/HotUI.iOS.csproj | 1 + src/HotUI.iOS/HotUIView.cs | 6 +- src/HotUI.iOS/ViewChangedEventArgs.cs | 22 ++++ src/HotUI.iOS/iOSViewHandler.cs | 10 +- src/HotUI/Controls/AbstractLayout.cs | 16 ++- src/HotUI/Controls/LayoutEventArgs.cs | 11 +- .../Xamarin.Forms.Loader.csproj | 2 +- 23 files changed, 194 insertions(+), 49 deletions(-) create mode 100644 src/HotUI.iOS/ViewChangedEventArgs.cs diff --git a/sample/Forms/HotUI.Forms.Sample.Android/HotUI.Forms.Sample.Android.csproj b/sample/Forms/HotUI.Forms.Sample.Android/HotUI.Forms.Sample.Android.csproj index c43a0f61..486a18b7 100644 --- a/sample/Forms/HotUI.Forms.Sample.Android/HotUI.Forms.Sample.Android.csproj +++ b/sample/Forms/HotUI.Forms.Sample.Android/HotUI.Forms.Sample.Android.csproj @@ -60,9 +60,9 @@ - + - 4.0.0.497661 + 4.1.0.581479 diff --git a/sample/Forms/HotUI.Forms.Sample.iOS/HotUI.Forms.Sample.iOS.csproj b/sample/Forms/HotUI.Forms.Sample.iOS/HotUI.Forms.Sample.iOS.csproj index 258bfede..d80554e0 100644 --- a/sample/Forms/HotUI.Forms.Sample.iOS/HotUI.Forms.Sample.iOS.csproj +++ b/sample/Forms/HotUI.Forms.Sample.iOS/HotUI.Forms.Sample.iOS.csproj @@ -126,9 +126,9 @@ - + - 4.0.0.497661 + 4.1.0.581479 diff --git a/sample/Forms/HotUI.Forms.Sample/HotUI.Forms.Sample.csproj b/sample/Forms/HotUI.Forms.Sample/HotUI.Forms.Sample.csproj index 8b02ad7d..86422873 100644 --- a/sample/Forms/HotUI.Forms.Sample/HotUI.Forms.Sample.csproj +++ b/sample/Forms/HotUI.Forms.Sample/HotUI.Forms.Sample.csproj @@ -15,8 +15,8 @@ 7.2 - - + + diff --git a/sample/HotUI.Android.Sample/HotUI.Android.Sample.csproj b/sample/HotUI.Android.Sample/HotUI.Android.Sample.csproj index f644baf8..cd43bff0 100644 --- a/sample/HotUI.Android.Sample/HotUI.Android.Sample.csproj +++ b/sample/HotUI.Android.Sample/HotUI.Android.Sample.csproj @@ -104,7 +104,7 @@ - + 2.4.11.982 diff --git a/sample/HotUI.Samples/MainPage.cs b/sample/HotUI.Samples/MainPage.cs index 45ecb87e..0c6c7d74 100644 --- a/sample/HotUI.Samples/MainPage.cs +++ b/sample/HotUI.Samples/MainPage.cs @@ -31,7 +31,7 @@ namespace HotUI.Samples { new MenuItem("SwiftUI Tutorial Section 4", ()=> new Section4()), new MenuItem("SwiftUI Tutorial Section 4b", ()=> new Section4b()), new MenuItem("SwiftUI Tutorial Section 4c", ()=> new Section4c()), - }; + }; public MainPage () { Body = () => new NavigationView { diff --git a/sample/HotUI.iOS.Sample/HotUI.iOS.Sample.csproj b/sample/HotUI.iOS.Sample/HotUI.iOS.Sample.csproj index 49b831d1..40f8bfb4 100644 --- a/sample/HotUI.iOS.Sample/HotUI.iOS.Sample.csproj +++ b/sample/HotUI.iOS.Sample/HotUI.iOS.Sample.csproj @@ -74,8 +74,8 @@ - - + + 2.4.11.982 diff --git a/src/HotUI.Android/HotUI.Android.csproj b/src/HotUI.Android/HotUI.Android.csproj index bf29432d..20c9ca06 100644 --- a/src/HotUI.Android/HotUI.Android.csproj +++ b/src/HotUI.Android/HotUI.Android.csproj @@ -87,7 +87,7 @@ - + diff --git a/src/HotUI.Forms/HotUI.Forms.csproj b/src/HotUI.Forms/HotUI.Forms.csproj index a1327f33..e216dca5 100644 --- a/src/HotUI.Forms/HotUI.Forms.csproj +++ b/src/HotUI.Forms/HotUI.Forms.csproj @@ -15,7 +15,7 @@ latest - + diff --git a/src/HotUI.iOS/Controls/HUIContainerView.cs b/src/HotUI.iOS/Controls/HUIContainerView.cs index bdd03bd6..3da49dc3 100644 --- a/src/HotUI.iOS/Controls/HUIContainerView.cs +++ b/src/HotUI.iOS/Controls/HUIContainerView.cs @@ -115,6 +115,9 @@ namespace HotUI.iOS.Controls get => _maskLayer; set { + if (_maskLayer != null) + _mainView.Layer.Mask = null; + _maskLayer = value; if (_mainView != null) _mainView.Layer.Mask = value; diff --git a/src/HotUI.iOS/Handlers/AbstractHandler.cs b/src/HotUI.iOS/Handlers/AbstractHandler.cs index 1bc5936b..6ae6a1e8 100644 --- a/src/HotUI.iOS/Handlers/AbstractHandler.cs +++ b/src/HotUI.iOS/Handlers/AbstractHandler.cs @@ -12,8 +12,9 @@ namespace HotUI.iOS private TVirtualView _virtualView; private TNativeView _nativeView; private HUIContainerView _containerView; - - public EventHandler ViewChanged { get; set; } + + public event EventHandler NativeViewChanged; + public event EventHandler RemovedFromView; protected AbstractHandler(PropertyMapper mapper) { @@ -39,12 +40,15 @@ namespace HotUI.iOS { if (!value && _containerView != null) { + var previousContainerView = _containerView; + _containerView.ShadowLayer = null; _containerView.MaskLayer = null; _containerView = null; + _nativeView.Layer.Mask = null; _nativeView.RemoveFromSuperview(); - ViewChanged?.Invoke(this, EventArgs.Empty); + NativeViewChanged?.Invoke(this, new ViewChangedEventArgs(VirtualView, previousContainerView, _nativeView)); return; } @@ -52,7 +56,7 @@ namespace HotUI.iOS { _containerView = new HUIContainerView(); _containerView.MainView = _nativeView; - ViewChanged?.Invoke(this, EventArgs.Empty); + NativeViewChanged?.Invoke(this, new ViewChangedEventArgs(VirtualView, _nativeView, _containerView)); } } } @@ -67,6 +71,8 @@ namespace HotUI.iOS _nativeView.RemoveFromSuperview(); _containerView = null; } + + RemovedFromView?.Invoke(this, EventArgs.Empty); } public virtual void SetView(View view) diff --git a/src/HotUI.iOS/Handlers/AbstractLayoutHandler.cs b/src/HotUI.iOS/Handlers/AbstractLayoutHandler.cs index f7a20cc8..81fe03b6 100644 --- a/src/HotUI.iOS/Handlers/AbstractLayoutHandler.cs +++ b/src/HotUI.iOS/Handlers/AbstractLayoutHandler.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Drawing; using CoreGraphics; @@ -14,8 +15,9 @@ namespace HotUI.iOS private Size _measured; private bool _measurementValid; - public AbstractLayout Layout => _view; - + public event EventHandler NativeViewChanged; + public event EventHandler RemovedFromView; + protected AbstractLayoutHandler(CGRect rect, ILayoutManager layoutManager) : base(rect) { _layoutManager = layoutManager; @@ -27,6 +29,8 @@ namespace HotUI.iOS _layoutManager = layoutManager; } + public AbstractLayout Layout => _view; + public Size Measure(UIView view, Size available) { CGSize size; @@ -85,6 +89,9 @@ namespace HotUI.iOS public void SetView(View view) { + if (_view != null) + Console.WriteLine("Removed should have been called beforehand."); + _view = view as AbstractLayout; if (_view != null) { @@ -92,9 +99,15 @@ namespace HotUI.iOS _view.ChildrenAdded += HandleChildrenAdded; _view.ChildrenRemoved += ViewOnChildrenRemoved; - foreach (var subView in _view) + foreach (var subview in _view) { - var nativeView = subView.ToView() ?? new UIView(); + if (subview.ViewHandler is iOSViewHandler handler) + { + handler.RemovedFromView += HandleHandlerRemovedFromView; + handler.NativeViewChanged += HandleSubviewChanged; + } + + var nativeView = subview.ToView() ?? new UIView(); AddSubview(nativeView); } @@ -105,16 +118,45 @@ namespace HotUI.iOS public void Remove(View view) { - foreach (var subview in Subviews) - subview.RemoveFromSuperview(); - - if (view != null) + foreach (var subview in _view) { - _view.ChildrenChanged -= HandleChildrenChanged; - _view.ChildrenAdded -= HandleChildrenAdded; - _view.ChildrenRemoved -= ViewOnChildrenRemoved; - _view = null; + if (subview.ViewHandler is iOSViewHandler handler) + { + handler.RemovedFromView -= HandleHandlerRemovedFromView; + handler.NativeViewChanged -= HandleSubviewChanged; + } } + + foreach (var subview in Subviews) + { + subview.RemoveFromSuperview(); + } + + _view.ChildrenChanged -= HandleChildrenChanged; + _view.ChildrenAdded -= HandleChildrenAdded; + _view.ChildrenRemoved -= ViewOnChildrenRemoved; + _view = null; + + RemovedFromView?.Invoke(this, EventArgs.Empty); + } + + private void HandleHandlerRemovedFromView(object sender, EventArgs e) + { + var handler = (iOSViewHandler)sender; + handler.RemovedFromView -= HandleHandlerRemovedFromView; + handler.NativeViewChanged -= HandleSubviewChanged; + } + + private void HandleSubviewChanged(object sender, ViewChangedEventArgs args) + { + Console.WriteLine($"HandlerViewChanged: [{sender.GetType()}] From:[{args.OldNativeView.GetType()}] To:[{args.NewNativeView.GetType()}]"); + + if (args.OldNativeView != null) + args.OldNativeView.RemoveFromSuperview(); + + var index = _view.IndexOf(args.VirtualView); + var newView = args.NewNativeView ?? new UIView(); + InsertSubview(newView, index); } public virtual void UpdateValue(string property, object value) @@ -133,6 +175,13 @@ namespace HotUI.iOS { var index = e.Start + i; var view = _view[index]; + + if (view.ViewHandler is iOSViewHandler handler) + { + handler.RemovedFromView += HandleHandlerRemovedFromView; + handler.NativeViewChanged += HandleSubviewChanged; + } + var nativeView = view.ToView() ?? new UIView(); InsertSubview(nativeView, index); } @@ -143,6 +192,18 @@ namespace HotUI.iOS private void ViewOnChildrenRemoved(object sender, LayoutEventArgs e) { + if (e.Removed != null) + { + foreach (var view in e.Removed) + { + if (view.ViewHandler is iOSViewHandler handler) + { + handler.RemovedFromView -= HandleHandlerRemovedFromView; + handler.NativeViewChanged -= HandleSubviewChanged; + } + } + } + for (var i = 0; i < e.Count; i++) { var index = e.Start + i; @@ -156,6 +217,18 @@ namespace HotUI.iOS private void HandleChildrenChanged(object sender, LayoutEventArgs e) { + if (e.Removed != null) + { + foreach (var view in e.Removed) + { + if (view.ViewHandler is iOSViewHandler handler) + { + handler.RemovedFromView -= HandleHandlerRemovedFromView; + handler.NativeViewChanged -= HandleSubviewChanged; + } + } + } + for (var i = 0; i < e.Count; i++) { var index = e.Start + i; @@ -163,6 +236,13 @@ namespace HotUI.iOS oldNativeView.RemoveFromSuperview(); var view = _view[index]; + + if (view.ViewHandler is iOSViewHandler handler) + { + handler.RemovedFromView += HandleHandlerRemovedFromView; + handler.NativeViewChanged += HandleSubviewChanged; + } + var newNativeView = view.ToView() ?? new UIView(); InsertSubview(newNativeView, index); } @@ -186,7 +266,7 @@ namespace HotUI.iOS } public override CGSize IntrinsicContentSize => _measured.ToCGSize(); - + public override void LayoutSubviews() { if (Superview == null || Bounds.Size.IsEmpty) diff --git a/src/HotUI.iOS/Handlers/ContentViewHandler.cs b/src/HotUI.iOS/Handlers/ContentViewHandler.cs index d3c6fb15..079ba3bf 100644 --- a/src/HotUI.iOS/Handlers/ContentViewHandler.cs +++ b/src/HotUI.iOS/Handlers/ContentViewHandler.cs @@ -12,7 +12,10 @@ namespace HotUI.iOS private ContentView _contentView; public UIView View => _view; - + + public event EventHandler NativeViewChanged; + public event EventHandler RemovedFromView; + public object NativeView => View; public HUIContainerView ContainerView => null; diff --git a/src/HotUI.iOS/Handlers/ListViewHandler.cs b/src/HotUI.iOS/Handlers/ListViewHandler.cs index 00a26a2f..81709c55 100644 --- a/src/HotUI.iOS/Handlers/ListViewHandler.cs +++ b/src/HotUI.iOS/Handlers/ListViewHandler.cs @@ -35,6 +35,9 @@ namespace HotUI.iOS public UIView View => this; + public event EventHandler NativeViewChanged; + public event EventHandler RemovedFromView; + public HUIContainerView ContainerView => null; public object NativeView => View; diff --git a/src/HotUI.iOS/Handlers/ScrollViewHandler.cs b/src/HotUI.iOS/Handlers/ScrollViewHandler.cs index e18f9c2a..a4915b4c 100644 --- a/src/HotUI.iOS/Handlers/ScrollViewHandler.cs +++ b/src/HotUI.iOS/Handlers/ScrollViewHandler.cs @@ -23,6 +23,9 @@ namespace HotUI.iOS public UIView View => this; + public event EventHandler NativeViewChanged; + public event EventHandler RemovedFromView; + public HUIContainerView ContainerView => null; public object NativeView => View; diff --git a/src/HotUI.iOS/Handlers/SpacerHandler.cs b/src/HotUI.iOS/Handlers/SpacerHandler.cs index 8d871267..c0ee679e 100644 --- a/src/HotUI.iOS/Handlers/SpacerHandler.cs +++ b/src/HotUI.iOS/Handlers/SpacerHandler.cs @@ -1,4 +1,5 @@ -using HotUI.iOS.Controls; +using System; +using HotUI.iOS.Controls; using UIKit; // ReSharper disable ClassNeverInstantiated.Global @@ -17,6 +18,9 @@ namespace HotUI.iOS public UIView View => this; + public event EventHandler NativeViewChanged; + public event EventHandler RemovedFromView; + public HUIContainerView ContainerView => null; public object NativeView => View; diff --git a/src/HotUI.iOS/Handlers/ViewHandler.cs b/src/HotUI.iOS/Handlers/ViewHandler.cs index b3327a9d..7b64b889 100644 --- a/src/HotUI.iOS/Handlers/ViewHandler.cs +++ b/src/HotUI.iOS/Handlers/ViewHandler.cs @@ -20,8 +20,9 @@ namespace HotUI.iOS private View _view; private UIView _body; - - public Action ViewChanged { get; set; } + + public event EventHandler NativeViewChanged; + public event EventHandler RemovedFromView; public UIView View => _body; @@ -39,10 +40,11 @@ namespace HotUI.iOS public void SetView(View view) { + var oldBody = _body; _view = view; SetBody(); Mapper.UpdateProperties(this, _view); - ViewChanged?.Invoke(); + NativeViewChanged?.Invoke(this, new ViewChangedEventArgs(_view, oldBody, _body)); } public void UpdateValue(string property, object value) @@ -137,7 +139,7 @@ namespace HotUI.iOS { var shadowLayer = new CAShapeLayer(); shadowLayer.Name = "shadow"; - shadowLayer.FillColor = new CGColor(0,0,0,0); + shadowLayer.FillColor = new CGColor(0,0,0,1); shadowLayer.Path = layer.Path; shadowLayer.Frame = layer.Frame; @@ -149,6 +151,7 @@ namespace HotUI.iOS } else { + nativeView.Layer.Mask = null; handler.HasContainer = false; } diff --git a/src/HotUI.iOS/HotUI.iOS.csproj b/src/HotUI.iOS/HotUI.iOS.csproj index 17b05dbe..e5f77eff 100644 --- a/src/HotUI.iOS/HotUI.iOS.csproj +++ b/src/HotUI.iOS/HotUI.iOS.csproj @@ -70,6 +70,7 @@ + diff --git a/src/HotUI.iOS/HotUIView.cs b/src/HotUI.iOS/HotUIView.cs index 998e9663..d89321c1 100644 --- a/src/HotUI.iOS/HotUIView.cs +++ b/src/HotUI.iOS/HotUIView.cs @@ -32,14 +32,14 @@ namespace HotUI.iOS _virtualView = value; _handler = _virtualView.ToIUIView(); if (_handler is ViewHandler viewHandler) - viewHandler.ViewChanged = HandleViewChanged; + viewHandler.NativeViewChanged += HandleViewChanged; - HandleViewChanged(); + HandleViewChanged(this, new ViewChangedEventArgs(_virtualView,null,null)); } } - void HandleViewChanged() + void HandleViewChanged(object sender, ViewChangedEventArgs args) { if (_virtualView == null) return; diff --git a/src/HotUI.iOS/ViewChangedEventArgs.cs b/src/HotUI.iOS/ViewChangedEventArgs.cs new file mode 100644 index 00000000..4da727e7 --- /dev/null +++ b/src/HotUI.iOS/ViewChangedEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using UIKit; + +namespace HotUI.iOS +{ + public class ViewChangedEventArgs : EventArgs + { + public View VirtualView { get; } + public UIView OldNativeView { get; } + public UIView NewNativeView { get; } + + public ViewChangedEventArgs( + View view, + UIView oldNativeView, + UIView newNativeView) + { + VirtualView = view; + OldNativeView = oldNativeView; + NewNativeView = newNativeView; + } + } +} diff --git a/src/HotUI.iOS/iOSViewHandler.cs b/src/HotUI.iOS/iOSViewHandler.cs index 467e516f..083e8192 100644 --- a/src/HotUI.iOS/iOSViewHandler.cs +++ b/src/HotUI.iOS/iOSViewHandler.cs @@ -5,7 +5,11 @@ namespace HotUI.iOS { public interface iOSViewHandler : IViewHandler { - UIView View { get; } - HUIContainerView ContainerView { get; } - } + event EventHandler NativeViewChanged; + event EventHandler RemovedFromView; + + UIView View { get; } + + HUIContainerView ContainerView { get; } + } } diff --git a/src/HotUI/Controls/AbstractLayout.cs b/src/HotUI/Controls/AbstractLayout.cs index 72bc75de..8a0f65b0 100644 --- a/src/HotUI/Controls/AbstractLayout.cs +++ b/src/HotUI/Controls/AbstractLayout.cs @@ -27,8 +27,9 @@ namespace HotUI var count = _views.Count; if (count > 0) { - _views.Clear (); - ChildrenRemoved?.Invoke (this, new LayoutEventArgs (0, count)); + var removed = new List(_views); + _views.Clear (); + ChildrenRemoved?.Invoke (this, new LayoutEventArgs (0, count, removed)); } } @@ -48,8 +49,9 @@ namespace HotUI item.Parent = null; item.Navigation = null; + var removed = new List { item }; _views.Remove (item); - ChildrenRemoved?.Invoke (this, new LayoutEventArgs (index, 1)); + ChildrenRemoved?.Invoke (this, new LayoutEventArgs (index, 1, removed)); return true; } @@ -87,8 +89,9 @@ namespace HotUI item.Parent = null; item.Navigation = null; + var removed = new List { item }; _views.RemoveAt(index); - ChildrenRemoved?.Invoke(this, new LayoutEventArgs(index, 1)); + ChildrenRemoved?.Invoke(this, new LayoutEventArgs(index, 1, removed)); } } @@ -100,13 +103,14 @@ namespace HotUI var item = _views[index]; item.Parent = null; item.Navigation = null; + var removed = new List { item }; - _views [index] = value; + _views[index] = value; value.Parent = null; value.Navigation = null; - ChildrenChanged?.Invoke (this, new LayoutEventArgs (index, 1)); + ChildrenChanged?.Invoke (this, new LayoutEventArgs (index, 1, removed)); } } diff --git a/src/HotUI/Controls/LayoutEventArgs.cs b/src/HotUI/Controls/LayoutEventArgs.cs index 462c6a13..10574836 100644 --- a/src/HotUI/Controls/LayoutEventArgs.cs +++ b/src/HotUI/Controls/LayoutEventArgs.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace HotUI { @@ -6,11 +7,19 @@ namespace HotUI { public int Start { get; } public int Count { get; } - + public List Removed { get; } + public LayoutEventArgs(int start, int count) { Start = start; Count = count; } + + public LayoutEventArgs(int start, int count, List removed) + { + Start = start; + Count = count; + Removed = removed; + } } } \ No newline at end of file diff --git a/src/Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj b/src/Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj index fbeca86d..91e963f8 100644 --- a/src/Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj +++ b/src/Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj @@ -5,6 +5,6 @@ - +