Xamarin.Forms: Change RelativeLayout constraints afterwards
It does not officially possible with the current version of Xamarin Forms. The RelativeLayout
container only recomputes constraints when adding/removing items from its children collection (it caches the solved constraints - presumable for performance). Even though the various constraints are implemented as Bindable Properties, they still do not get recomputed when changed.
I assume that the intention is to someday respect constraint updates, which would be useful with animations for example, but for now it doesn't appear to work that way.
HOWEVER, I took a look at the decompiled source for RelativeLayout and it is possible to hack together a way around it - but it might not suit your needs, depending on how much functionality you require and how complex your constraint definitions are.
See this example code (the key part is setting the constraint using SetBoundsConstraint, which overrides the internally computed bounds of the added view - and then calling ForceLayout()
):
public partial class App : Application
{
public App ()
{
var label = new Label {
Text = "Test",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
BackgroundColor = Color.Silver
};
var layout = new RelativeLayout ();
layout.Children.Add (label,
Constraint.Constant (50),
Constraint.Constant (100),
Constraint.Constant (260),
Constraint.Constant (30));
MainPage = new ContentPage {
Content = layout
};
var fwd = true;
layout.Animate ("bounce",
(delta) => {
var d = fwd ? delta : 1.0 - delta;
var y = 100.0 + (50.0 * d);
var c = BoundsConstraint.FromExpression ((Expression<Func<Rectangle>>)(() => new Rectangle (50, y, 260, 30)), new View [0]);
RelativeLayout.SetBoundsConstraint(label, c);
layout.ForceLayout ();
}, 16, 800, Easing.SinInOut, (f, b) => {
// reset direction
fwd = !fwd;
}, () => {
// keep bouncing
return true;
});
}
}
Yes. This possible. Layout code:
<StackLayout RelativeLayout.XConstraint="{Binding XConstaint}" ...>
VM code:
public Constraint XConstaint
{
get => _xConstaint;
set { SetFieldValue(ref _xConstaint, value, nameof(XConstaint)); }
}
public override void OnAppearing()
{
base.OnAppearing();
XConstaint = Constraint.RelativeToParent((parent) => { return parent.Width - 128; });
}