summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Leybaert <philippe@activa.be>2017-02-02 12:55:55 -0600
committerKangho Hur <kangho.hur@samsung.com>2017-03-24 13:18:57 +0900
commit1c019470b9c2af3a1f9ab25252b23327ca5e351a (patch)
treedc95dcb1b491236ae6975441e4fc5e5ba4650db3
parentb50a12b136ef17b0bf46103821481d92ec3b2dae (diff)
downloadxamarin-forms-1c019470b9c2af3a1f9ab25252b23327ca5e351a.tar.gz
xamarin-forms-1c019470b9c2af3a1f9ab25252b23327ca5e351a.tar.bz2
xamarin-forms-1c019470b9c2af3a1f9ab25252b23327ca5e351a.zip
Update RelativeLayout to make it respond to constraint changes (#425)
* Update RelativeLayout to make it respond to constraint changes Constraints of a RelativeLayout are bindable properties but the layout does not update when the constraints are updated. This change will invalidate the layout whenever XConstraint, YConstraint, WidthConstraint or HeightConstraint is changed (either in code or through a change in the bound property) * Specified changed handler as named property * Adding attached property accessors for layout properties Since the constraint attached properties can now be updated at runtime, setters are required for those properties. Also, when adding a child view at runtime using the Add() method with x/y/w/h constraints, generating the bounds constraints is deferred to the layout phase. * Unit tests for runtime constraints updates in RelativeLayout * Rename unit test method Rename LayoutChangesAtRuntim() to LayoutIsUpdatedWhenConstraintsChange() * Wrap RelativeLayout update setters in BatchBegin/Commit * Update documentation of RelativeLayout Added SetXConstraint(), SetYConstraint(), SetWidthConstraint() and SetHeightConstraint()
-rw-r--r--Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs41
-rw-r--r--Xamarin.Forms.Core/RelativeLayout.cs62
-rw-r--r--docs/Xamarin.Forms.Core/Xamarin.Forms/RelativeLayout.xml84
3 files changed, 179 insertions, 8 deletions
diff --git a/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs b/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs
index 96b3dfc8..fdbcdfc0 100644
--- a/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs
+++ b/Xamarin.Forms.Core.UnitTests/RelativeLayoutTests.cs
@@ -75,6 +75,47 @@ namespace Xamarin.Forms.Core.UnitTests
}
[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 ()
{
var relativeLayout = new RelativeLayout {
diff --git a/Xamarin.Forms.Core/RelativeLayout.cs b/Xamarin.Forms.Core/RelativeLayout.cs
index b3a1b615..2b835013 100644
--- a/Xamarin.Forms.Core/RelativeLayout.cs
+++ b/Xamarin.Forms.Core/RelativeLayout.cs
@@ -8,13 +8,13 @@ namespace Xamarin.Forms
{
public class RelativeLayout : Layout<View>
{
- 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 @@ namespace Xamarin.Forms
}
}
+ 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 @@ namespace Xamarin.Forms
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 @@ namespace Xamarin.Forms
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 @@ namespace Xamarin.Forms
public void Add(View view, Expression<Func<Rectangle>> 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 @@ namespace Xamarin.Forms
public void Add(View view, Constraint xConstraint = null, Constraint yConstraint = null, Constraint widthConstraint = null, Constraint heightConstraint = null)
{
- Parent.CreateBoundsFromConstraints(view, xConstraint, yConstraint, widthConstraint, heightConstraint);
+ view.BatchBegin();
+
+ RelativeLayout.SetXConstraint(view, xConstraint);
+ RelativeLayout.SetYConstraint(view, yConstraint);
+ RelativeLayout.SetWidthConstraint(view, widthConstraint);
+ RelativeLayout.SetHeightConstraint(view, heightConstraint);
+
+ view.BatchCommit();
base.Add(view);
}
diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/RelativeLayout.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/RelativeLayout.xml
index 8d1082e9..6a8c498b 100644
--- a/docs/Xamarin.Forms.Core/Xamarin.Forms/RelativeLayout.xml
+++ b/docs/Xamarin.Forms.Core/Xamarin.Forms/RelativeLayout.xml
@@ -446,6 +446,90 @@ public class RelativeLayoutExample : ContentPage
<remarks>To be added.</remarks>
</Docs>
</Member>
+ <Member MemberName="SetHeightConstraint">
+ <MemberSignature Language="C#" Value="public static void SetHeightConstraint (Xamarin.Forms.BindableObject bindable, Xamarin.Forms.Constraint value);" />
+ <MemberSignature Language="ILAsm" Value=".method public static hidebysig void SetHeightConstraint(class Xamarin.Forms.BindableObject bindable, class Xamarin.Forms.Constraint value) cil managed" />
+ <MemberType>Method</MemberType>
+ <AssemblyInfo>
+ <AssemblyVersion>2.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name="bindable" Type="Xamarin.Forms.BindableObject" />
+ <Parameter Name="value" Type="Xamarin.Forms.Constraint" />
+ </Parameters>
+ <Docs>
+ <param name="bindable">The <see cref="T:Xamarin.Forms.BindableObject" /> to which the constraint will be applied.</param>
+ <param name="value">The <see cref="T:Xamarin.Forms.Constraint" /> on the height of the <paramref name="bindable" />.</param>
+ <summary>Sets <paramref name="value" /> as a constraint on the height of the <paramref name="bindable" />.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
+ <Member MemberName="SetWidthConstraint">
+ <MemberSignature Language="C#" Value="public static void SetWidthConstraint (Xamarin.Forms.BindableObject bindable, Xamarin.Forms.Constraint value);" />
+ <MemberSignature Language="ILAsm" Value=".method public static hidebysig void SetWidthConstraint(class Xamarin.Forms.BindableObject bindable, class Xamarin.Forms.Constraint value) cil managed" />
+ <MemberType>Method</MemberType>
+ <AssemblyInfo>
+ <AssemblyVersion>2.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name="bindable" Type="Xamarin.Forms.BindableObject" />
+ <Parameter Name="value" Type="Xamarin.Forms.Constraint" />
+ </Parameters>
+ <Docs>
+ <param name="bindable">The <see cref="T:Xamarin.Forms.BindableObject" /> to which the constraint will be applied.</param>
+ <param name="value">The <see cref="T:Xamarin.Forms.Constraint" /> on the width of the <paramref name="bindable" />.</param>
+ <summary>Sets <paramref name="value" /> as a constraint on the width of the <paramref name="bindable" />.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
+ <Member MemberName="SetXConstraint">
+ <MemberSignature Language="C#" Value="public static void SetXConstraint (Xamarin.Forms.BindableObject bindable, Xamarin.Forms.Constraint value);" />
+ <MemberSignature Language="ILAsm" Value=".method public static hidebysig void SetXConstraint(class Xamarin.Forms.BindableObject bindable, class Xamarin.Forms.Constraint value) cil managed" />
+ <MemberType>Method</MemberType>
+ <AssemblyInfo>
+ <AssemblyVersion>2.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name="bindable" Type="Xamarin.Forms.BindableObject" />
+ <Parameter Name="value" Type="Xamarin.Forms.Constraint" />
+ </Parameters>
+ <Docs>
+ <param name="bindable">The <see cref="T:Xamarin.Forms.BindableObject" /> to which the constraint will be applied.</param>
+ <param name="value">The <see cref="T:Xamarin.Forms.Constraint" /> on the X position of the <paramref name="bindable" />.</param>
+ <summary>Sets <paramref name="value" /> as a constraint on the X position of the <paramref name="bindable" />.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
+ <Member MemberName="SetYConstraint">
+ <MemberSignature Language="C#" Value="public static void SetYConstraint (Xamarin.Forms.BindableObject bindable, Xamarin.Forms.Constraint value);" />
+ <MemberSignature Language="ILAsm" Value=".method public static hidebysig void SetYConstraint(class Xamarin.Forms.BindableObject bindable, class Xamarin.Forms.Constraint value) cil managed" />
+ <MemberType>Method</MemberType>
+ <AssemblyInfo>
+ <AssemblyVersion>2.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <ReturnValue>
+ <ReturnType>System.Void</ReturnType>
+ </ReturnValue>
+ <Parameters>
+ <Parameter Name="bindable" Type="Xamarin.Forms.BindableObject" />
+ <Parameter Name="value" Type="Xamarin.Forms.Constraint" />
+ </Parameters>
+ <Docs>
+ <param name="bindable">The <see cref="T:Xamarin.Forms.BindableObject" /> to which the constraint will be applied.</param>
+ <param name="value">The <see cref="T:Xamarin.Forms.Constraint" /> on the Y position of the <paramref name="bindable" />.</param>
+ <summary>Sets <paramref name="value" /> as a constraint on the Y position of the <paramref name="bindable" />.</summary>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
<Member MemberName="WidthConstraintProperty">
<MemberSignature Language="C#" Value="public static readonly Xamarin.Forms.BindableProperty WidthConstraintProperty;" />
<MemberSignature Language="ILAsm" Value=".field public static initonly class Xamarin.Forms.BindableProperty WidthConstraintProperty" />