diff --git a/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs b/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs index 96b3dfc8f88..fdbcdfc0075 100644 --- a/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs +++ b/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs @@ -74,6 +74,47 @@ public void SimpleLayout () Assert.AreEqual (new Rectangle (30, 20, 50, 25), child.Bounds); } + [Test] + public void LayoutIsUpdatedWhenConstraintsChange() + { + var relativeLayout = new RelativeLayout + { + Platform = new UnitPlatform(), + IsPlatformEnabled = true + }; + + var child = new View + { + IsPlatformEnabled = true + }; + + relativeLayout.Children.Add(child, + Constraint.Constant(30), + Constraint.Constant(20), + Constraint.RelativeToParent(parent => parent.Height / 2), + Constraint.RelativeToParent(parent => parent.Height / 4)); + + relativeLayout.Layout(new Rectangle(0, 0, 100, 100)); + + Assert.AreEqual(new Rectangle(30, 20, 50, 25), child.Bounds); + + RelativeLayout.SetXConstraint(child, Constraint.Constant(40)); + + Assert.AreEqual(new Rectangle(40, 20, 50, 25), child.Bounds); + + RelativeLayout.SetYConstraint(child, Constraint.Constant(10)); + + Assert.AreEqual(new Rectangle(40, 10, 50, 25), child.Bounds); + + RelativeLayout.SetWidthConstraint(child, Constraint.RelativeToParent(parent => parent.Height / 4)); + + Assert.AreEqual(new Rectangle(40, 10, 25, 25), child.Bounds); + + RelativeLayout.SetHeightConstraint(child, Constraint.RelativeToParent(parent => parent.Height / 2)); + + Assert.AreEqual(new Rectangle(40, 10, 25, 50), child.Bounds); + } + [Test] public void SimpleExpressionLayout () { diff --git a/Xamarin.Forms.Core/RelativeLayout.cs b/Xamarin.Forms.Core/RelativeLayout.cs index b3a1b61570c..2b835013f86 100644 --- a/Xamarin.Forms.Core/RelativeLayout.cs +++ b/Xamarin.Forms.Core/RelativeLayout.cs @@ -8,13 +8,13 @@ namespace Xamarin.Forms { public class RelativeLayout : Layout { - public static readonly BindableProperty XConstraintProperty = BindableProperty.CreateAttached("XConstraint", typeof(Constraint), typeof(RelativeLayout), null); + public static readonly BindableProperty XConstraintProperty = BindableProperty.CreateAttached("XConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); - public static readonly BindableProperty YConstraintProperty = BindableProperty.CreateAttached("YConstraint", typeof(Constraint), typeof(RelativeLayout), null); + public static readonly BindableProperty YConstraintProperty = BindableProperty.CreateAttached("YConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); - public static readonly BindableProperty WidthConstraintProperty = BindableProperty.CreateAttached("WidthConstraint", typeof(Constraint), typeof(RelativeLayout), null); + public static readonly BindableProperty WidthConstraintProperty = BindableProperty.CreateAttached("WidthConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); - public static readonly BindableProperty HeightConstraintProperty = BindableProperty.CreateAttached("HeightConstraint", typeof(Constraint), typeof(RelativeLayout), null); + public static readonly BindableProperty HeightConstraintProperty = BindableProperty.CreateAttached("HeightConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); public static readonly BindableProperty BoundsConstraintProperty = BindableProperty.CreateAttached("BoundsConstraint", typeof(BoundsConstraint), typeof(RelativeLayout), null); @@ -72,6 +72,25 @@ IEnumerable ChildrenInSolveOrder } } + static void ConstraintChanged(BindableObject bindable, object oldValue, object newValue) + { + View view = bindable as View; + + (view?.Parent as RelativeLayout)?.UpdateBoundsConstraint(view); + } + + void UpdateBoundsConstraint(View view) + { + if (GetBoundsConstraint(view) == null) + return; // Bounds constraint hasn't been calculated yet, no need to update just yet + + CreateBoundsFromConstraints(view, GetXConstraint(view), GetYConstraint(view), GetWidthConstraint(view), GetHeightConstraint(view)); + + _childrenInSolveOrder = null; // New constraints may have impact on solve order + + InvalidateLayout(); + } + public static BoundsConstraint GetBoundsConstraint(BindableObject bindable) { return (BoundsConstraint)bindable.GetValue(BoundsConstraintProperty); @@ -102,6 +121,26 @@ public static void SetBoundsConstraint(BindableObject bindable, BoundsConstraint bindable.SetValue(BoundsConstraintProperty, value); } + public static void SetHeightConstraint(BindableObject bindable, Constraint value) + { + bindable.SetValue(HeightConstraintProperty, value); + } + + public static void SetWidthConstraint(BindableObject bindable, Constraint value) + { + bindable.SetValue(WidthConstraintProperty, value); + } + + public static void SetXConstraint(BindableObject bindable, Constraint value) + { + bindable.SetValue(XConstraintProperty, value); + } + + public static void SetYConstraint(BindableObject bindable, Constraint value) + { + bindable.SetValue(YConstraintProperty, value); + } + protected override void LayoutChildren(double x, double y, double width, double height) { foreach (View child in ChildrenInSolveOrder) @@ -248,13 +287,13 @@ void CreateBoundsFromConstraints(View view, Constraint xConstraint, Constraint y static Rectangle SolveView(View view) { BoundsConstraint boundsConstraint = GetBoundsConstraint(view); - var result = new Rectangle(); if (boundsConstraint == null) { throw new Exception("BoundsConstraint should not be null at this point"); } - result = boundsConstraint.Compute(); + + var result = boundsConstraint.Compute(); return result; } @@ -280,7 +319,7 @@ public RelativeElementCollection(ObservableCollection inner, RelativeLa public void Add(View view, Expression> bounds) { if (bounds == null) - throw new ArgumentNullException("bounds"); + throw new ArgumentNullException(nameof(bounds)); SetBoundsConstraint(view, BoundsConstraint.FromExpression(bounds)); base.Add(view); @@ -308,7 +347,14 @@ public void Add(View view, Expression> x = null, ExpressionTo be added. + + + + Method + + 2.0.0.0 + + + System.Void + + + + + + + The to which the constraint will be applied. + The on the height of the . + Sets as a constraint on the height of the . + To be added. + + + + + + Method + + 2.0.0.0 + + + System.Void + + + + + + + The to which the constraint will be applied. + The on the width of the . + Sets as a constraint on the width of the . + To be added. + + + + + + Method + + 2.0.0.0 + + + System.Void + + + + + + + The to which the constraint will be applied. + The on the X position of the . + Sets as a constraint on the X position of the . + To be added. + + + + + + Method + + 2.0.0.0 + + + System.Void + + + + + + + The to which the constraint will be applied. + The on the Y position of the . + Sets as a constraint on the Y position of the . + To be added. + +