diff --git a/src/ControlGallery/src/Xamarin.Forms.Controls/CoreGallery.cs b/src/ControlGallery/src/Xamarin.Forms.Controls/CoreGallery.cs index a8e05a401..5fb7123c9 100644 --- a/src/ControlGallery/src/Xamarin.Forms.Controls/CoreGallery.cs +++ b/src/ControlGallery/src/Xamarin.Forms.Controls/CoreGallery.cs @@ -298,6 +298,7 @@ namespace Xamarin.Forms.Controls } List _pages = new List { + new GalleryPageFactory(() => new GalleryPages.LayoutGalleries.LayoutGallery(), ".NET MAUI Layouts"), new GalleryPageFactory(() => new TabIndexTest.TabIndex(), "Accessibility TabIndex (2)"), new GalleryPageFactory(() => new PlatformTestsConsole(), "Platform Automated Tests"), new GalleryPageFactory(() => new EmbeddedFonts(), "Embedded Fonts"), diff --git a/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/HorizontalStackLayoutGallery.cs b/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/HorizontalStackLayoutGallery.cs new file mode 100644 index 000000000..2ce475a61 --- /dev/null +++ b/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/HorizontalStackLayoutGallery.cs @@ -0,0 +1,17 @@ +namespace Xamarin.Forms.Controls.GalleryPages.LayoutGalleries +{ + public class HorizontalStackLayoutGallery : ContentPage + { + public HorizontalStackLayoutGallery() + { + var layout = new HorizontalStackLayout(); + + for (int n = 0; n < 3; n++) + { + layout.Add(new Label { Text = $"Label {n} in a horizontal stack" }); + } + + Content = layout; + } + } +} diff --git a/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/LayoutGallery.cs b/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/LayoutGallery.cs new file mode 100644 index 000000000..d19358b30 --- /dev/null +++ b/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/LayoutGallery.cs @@ -0,0 +1,20 @@ +namespace Xamarin.Forms.Controls.GalleryPages.LayoutGalleries +{ + public class LayoutGallery : ContentPage + { + public LayoutGallery() + { + Content = new ScrollView + { + Content = new StackLayout + { + Children = + { + GalleryBuilder.NavButton("VerticalStackLayout Gallery", () => new VerticalStackLayoutGallery(), Navigation), + GalleryBuilder.NavButton("HorizontalStackLayout Gallery", () => new HorizontalStackLayoutGallery(), Navigation), + } + } + }; + } + } +} diff --git a/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/VerticalStackLayoutGallery.cs b/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/VerticalStackLayoutGallery.cs new file mode 100644 index 000000000..a1187187a --- /dev/null +++ b/src/ControlGallery/src/Xamarin.Forms.Controls/GalleryPages/LayoutGalleries/VerticalStackLayoutGallery.cs @@ -0,0 +1,17 @@ +namespace Xamarin.Forms.Controls.GalleryPages.LayoutGalleries +{ + public class VerticalStackLayoutGallery : ContentPage + { + public VerticalStackLayoutGallery() + { + var layout = new VerticalStackLayout(); + + for (int n = 0; n < 10; n++) + { + layout.Add(new Label { Text = $"Label {n} in a vertical stack" }); + } + + Content = layout; + } + } +} diff --git a/src/Forms/src/Xamarin.Forms.Core/FormsHandlers.cs b/src/Forms/src/Xamarin.Forms.Core/FormsHandlers.cs index 0d17c5c50..8d80a6cf6 100644 --- a/src/Forms/src/Xamarin.Forms.Core/FormsHandlers.cs +++ b/src/Forms/src/Xamarin.Forms.Core/FormsHandlers.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Xamarin.Platform.Handlers; namespace Xamarin.Forms { @@ -15,6 +16,9 @@ namespace Xamarin.Forms //Xamarin.Platform.Registrar.Handlers.Register(typeof(Slider), typeof(Xamarin.Platform.Handlers.SliderHandler)); //Xamarin.Platform.Registrar.Handlers.Register(typeof(Button), typeof(Xamarin.Platform.Handlers.ButtonHandler)); //RegistrarHandlers.Handlers.Register(); + + Xamarin.Platform.Registrar.Handlers.Register(); + Xamarin.Platform.Registrar.Handlers.Register(); } } } diff --git a/src/Forms/src/Xamarin.Forms.Core/Layout/HorizontalStackLayout.cs b/src/Forms/src/Xamarin.Forms.Core/Layout/HorizontalStackLayout.cs new file mode 100644 index 000000000..99448b207 --- /dev/null +++ b/src/Forms/src/Xamarin.Forms.Core/Layout/HorizontalStackLayout.cs @@ -0,0 +1,11 @@ +using Xamarin.Platform.Layouts; + +namespace Xamarin.Forms +{ + // Don't panic, Layout2.StackLayout is the temporary name for the abstract base class until + // we rename everything and move the legacy layouts + public class HorizontalStackLayout : Layout2.StackLayout + { + protected override ILayoutManager CreateLayoutManager() => new HorizontalStackLayoutManager(this); + } +} diff --git a/src/Platform.Handlers/samples/Sample/Controls/Layout.cs b/src/Forms/src/Xamarin.Forms.Core/Layout/Layout.cs similarity index 83% rename from src/Platform.Handlers/samples/Sample/Controls/Layout.cs rename to src/Forms/src/Xamarin.Forms.Core/Layout/Layout.cs index 4bb131e11..aa4e0503b 100644 --- a/src/Platform.Handlers/samples/Sample/Controls/Layout.cs +++ b/src/Forms/src/Xamarin.Forms.Core/Layout/Layout.cs @@ -1,11 +1,10 @@ using System.Collections; using System.Collections.Generic; -using Xamarin.Forms; using Xamarin.Platform; -using Xamarin.Platform.Handlers; using Xamarin.Platform.Layouts; -namespace Sample +// This is a temporary namespace until we rename everything and move the legacy layouts +namespace Xamarin.Forms.Layout2 { public abstract class Layout : View, Xamarin.Platform.ILayout, IEnumerable { @@ -24,7 +23,7 @@ namespace Sample IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator(); - public override Size Measure(double widthConstraint, double heightConstraint) + protected override Size MeasureOverride(double widthConstraint, double heightConstraint) { if (IsMeasureValid) { @@ -39,7 +38,7 @@ namespace Sample return DesiredSize; } - public override void Arrange(Rectangle bounds) + protected override void ArrangeOverride(Rectangle bounds) { if (IsArrangeValid) { @@ -53,7 +52,7 @@ namespace Sample Handler?.SetFrame(Frame); } - public override void InvalidateMeasure() + protected override void InvalidateMeasureOverride() { base.InvalidateMeasure(); diff --git a/src/Platform.Handlers/samples/Sample/Controls/StackLayout.cs b/src/Forms/src/Xamarin.Forms.Core/Layout/StackLayout.cs similarity index 75% rename from src/Platform.Handlers/samples/Sample/Controls/StackLayout.cs rename to src/Forms/src/Xamarin.Forms.Core/Layout/StackLayout.cs index 2dc5f7400..1436c4b06 100644 --- a/src/Platform.Handlers/samples/Sample/Controls/StackLayout.cs +++ b/src/Forms/src/Xamarin.Forms.Core/Layout/StackLayout.cs @@ -1,8 +1,8 @@ using System.Linq; -using System.Runtime.InteropServices; using Xamarin.Platform; -namespace Sample +// This is a temporary namespace until we rename everything and move the legacy layouts +namespace Xamarin.Forms.Layout2 { public abstract class StackLayout : Layout, IStackLayout { diff --git a/src/Forms/src/Xamarin.Forms.Core/Layout/VerticalStackLayout.cs b/src/Forms/src/Xamarin.Forms.Core/Layout/VerticalStackLayout.cs new file mode 100644 index 000000000..3c153e1a2 --- /dev/null +++ b/src/Forms/src/Xamarin.Forms.Core/Layout/VerticalStackLayout.cs @@ -0,0 +1,11 @@ +using Xamarin.Platform.Layouts; + +namespace Xamarin.Forms +{ + // Don't panic, Layout2.StackLayout is the temporary name for the abstract base class until + // we rename everything and move the legacy layout + public class VerticalStackLayout : Layout2.StackLayout + { + protected override ILayoutManager CreateLayoutManager() => new VerticalStackLayoutManager(this); + } +} diff --git a/src/Forms/src/Xamarin.Forms.Core/RadioButton.cs b/src/Forms/src/Xamarin.Forms.Core/RadioButton.cs index 870bf2047..5cd9484c8 100644 --- a/src/Forms/src/Xamarin.Forms.Core/RadioButton.cs +++ b/src/Forms/src/Xamarin.Forms.Core/RadioButton.cs @@ -434,7 +434,7 @@ namespace Xamarin.Forms Padding = 6 }; - BindToTemplatedParent(frame, BackgroundColorProperty, Frame.BorderColorProperty, HorizontalOptionsProperty, + BindToTemplatedParent(frame, BackgroundColorProperty, Xamarin.Forms.Frame.BorderColorProperty, HorizontalOptionsProperty, MarginProperty, OpacityProperty, RotationProperty, ScaleProperty, ScaleXProperty, ScaleYProperty, TranslationYProperty, TranslationXProperty, VerticalOptionsProperty); diff --git a/src/Forms/src/Xamarin.Forms.Core/View.cs b/src/Forms/src/Xamarin.Forms.Core/View.cs index d5dd413ff..cff528fe8 100644 --- a/src/Forms/src/Xamarin.Forms.Core/View.cs +++ b/src/Forms/src/Xamarin.Forms.Core/View.cs @@ -176,7 +176,7 @@ namespace Xamarin.Forms #region IView - Rectangle IFrameworkElement.Frame => Bounds; + public Rectangle Frame => Bounds; public IViewHandler Handler { @@ -194,7 +194,7 @@ namespace Xamarin.Forms public Size DesiredSize { get; protected set; } - public bool IsMeasureValid { get; protected set; } + public virtual bool IsMeasureValid { get; protected set; } public bool IsArrangeValid { get; protected set; } @@ -204,6 +204,13 @@ namespace Xamarin.Forms } void IFrameworkElement.Arrange(Rectangle bounds) + { + ArrangeOverride(bounds); + } + + // ArrangeOverride provides a way to allow subclasses (e.g., Layout) to override Arrange even though + // the interface has to be explicitly implemented to avoid conflict with the old Arrange method + protected virtual void ArrangeOverride(Rectangle bounds) { if (IsArrangeValid) return; @@ -218,10 +225,21 @@ namespace Xamarin.Forms protected override void OnSizeAllocated(double width, double height) { base.OnSizeAllocated(width, height); - Handler?.SetFrame(Bounds); + + if (IsArrangeValid) + { + Handler?.SetFrame(Bounds); + } } Size IFrameworkElement.Measure(double widthConstraint, double heightConstraint) + { + return MeasureOverride(widthConstraint, heightConstraint); + } + + // ArrangeOverride provides a way to allow subclasses (e.g., Layout) to override Measure even though + // the interface has to be explicitly implemented to avoid conflict with the old Measure method + protected virtual Size MeasureOverride(double widthConstraint, double heightConstraint) { if (!IsMeasureValid) { @@ -233,6 +251,13 @@ namespace Xamarin.Forms } void IFrameworkElement.InvalidateMeasure() + { + InvalidateMeasureOverride(); + } + + // ArrangeOverride provides a way to allow subclasses (e.g., Layout) to override InvalidateMeasure even though + // the interface has to be explicitly implemented to avoid conflict with the VisualElement.InvalidateMeasure method + protected virtual void InvalidateMeasureOverride() { IsMeasureValid = false; IsArrangeValid = false; diff --git a/src/Platform.Handlers/samples/Sample.iOS/AppDelegate.cs b/src/Platform.Handlers/samples/Sample.iOS/AppDelegate.cs index deccb2e4f..aa7082b19 100644 --- a/src/Platform.Handlers/samples/Sample.iOS/AppDelegate.cs +++ b/src/Platform.Handlers/samples/Sample.iOS/AppDelegate.cs @@ -2,8 +2,8 @@ using UIKit; using Xamarin.Platform; -#if !NET6_0 using Xamarin.Forms; +#if !NET6_0 using Xamarin.Forms.Platform.iOS; #endif diff --git a/src/Platform.Handlers/samples/Sample/Controls/HorizontalStackLayout.cs b/src/Platform.Handlers/samples/Sample/Controls/HorizontalStackLayout.cs deleted file mode 100644 index 7acdf6e33..000000000 --- a/src/Platform.Handlers/samples/Sample/Controls/HorizontalStackLayout.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Xamarin.Platform.Layouts; - -namespace Sample -{ - public class HorizontalStackLayout : StackLayout - { - protected override ILayoutManager CreateLayoutManager() => new HorizontalStackLayoutManager(this); - } -} diff --git a/src/Platform.Handlers/samples/Sample/Controls/VerticalStackLayout.cs b/src/Platform.Handlers/samples/Sample/Controls/VerticalStackLayout.cs deleted file mode 100644 index d5dd00f3e..000000000 --- a/src/Platform.Handlers/samples/Sample/Controls/VerticalStackLayout.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Xamarin.Platform.Layouts; - -namespace Sample -{ - public class VerticalStackLayout : StackLayout - { - protected override ILayoutManager CreateLayoutManager() => new VerticalStackLayoutManager(this); - } -} diff --git a/src/Platform.Handlers/samples/Sample/Platform.cs b/src/Platform.Handlers/samples/Sample/Platform.cs index 8fad09f36..e63b5f7e1 100644 --- a/src/Platform.Handlers/samples/Sample/Platform.cs +++ b/src/Platform.Handlers/samples/Sample/Platform.cs @@ -22,8 +22,8 @@ namespace Sample RegistrarHandlers.Handlers.Register(); RegistrarHandlers.Handlers.Register(); - RegistrarHandlers.Handlers.Register(); - RegistrarHandlers.Handlers.Register(); + RegistrarHandlers.Handlers.Register(); + RegistrarHandlers.Handlers.Register(); RegistrarHandlers.Handlers.Register(); RegistrarHandlers.Handlers.Register(); //RegistrarHandlers.Handlers.Register(); diff --git a/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Core/IFrameworkElement.cs b/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Core/IFrameworkElement.cs index 35fc03760..53ae3ea4e 100644 --- a/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Core/IFrameworkElement.cs +++ b/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Core/IFrameworkElement.cs @@ -25,6 +25,5 @@ namespace Xamarin.Platform double Height { get; } Thickness Margin { get; } - } } \ No newline at end of file diff --git a/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Registrar.cs b/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Registrar.cs index 07ea4c317..ac3d2f061 100644 --- a/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Registrar.cs +++ b/src/Platform.Handlers/src/Xamarin.Platform.Handlers/Registrar.cs @@ -126,7 +126,7 @@ namespace Xamarin.Platform { var newObject = Activator.CreateInstance(handler); - if(newObject == null) + if (newObject == null) throw new ArgumentException($"No Handler found for type: {type}", nameof(type)); return (TTypeRender)newObject; diff --git a/src/Platform.Renderers/src/Xamarin.Forms.Platform.Android/HandlerToRendererShim.cs b/src/Platform.Renderers/src/Xamarin.Forms.Platform.Android/HandlerToRendererShim.cs index 3c3fc7707..0e49fd30b 100644 --- a/src/Platform.Renderers/src/Xamarin.Forms.Platform.Android/HandlerToRendererShim.cs +++ b/src/Platform.Renderers/src/Xamarin.Forms.Platform.Android/HandlerToRendererShim.cs @@ -51,7 +51,10 @@ namespace Xamarin.Forms Element.PropertyChanged += OnElementPropertyChanged; Element = element; + ViewHandler.SetVirtualView((IView)element); + ((IView)element).Handler = ViewHandler; + if (Tracker == null) { Tracker = new VisualElementTracker(this); diff --git a/src/Platform.Renderers/src/Xamarin.Forms.Platform.iOS/HandlerToRendererShim.cs b/src/Platform.Renderers/src/Xamarin.Forms.Platform.iOS/HandlerToRendererShim.cs index ad7801393..6d1e5e575 100644 --- a/src/Platform.Renderers/src/Xamarin.Forms.Platform.iOS/HandlerToRendererShim.cs +++ b/src/Platform.Renderers/src/Xamarin.Forms.Platform.iOS/HandlerToRendererShim.cs @@ -39,6 +39,8 @@ namespace Xamarin.Forms.Platform.iOS Element = element; ViewHandler.SetVirtualView((IView)element); + ((IView)element).Handler = ViewHandler; + ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(oldElement, Element)); }