Jordi Corominas
Jordi Corominas

Reputation: 1244

How to bind a NSLayoutConstraint's constant properly?

I'm developing an app with Xamarin and MVVMCross and I'm having problems creating binding NSLayoutConstraints constants.

I have a view with a Subview that should "disapear" if a certain List<> has no elements, and the content below should move up instead of leaving it's space empty.

To do that I added an NSLayoutConstraint to this view to be able to modify it's height programmatically and I bind it with the following line of code:

var set = this.CreateBindingSet<ActivityView, ActivityViewModel> ();
set.Bind (ConstraintHeightPictures).To (vm => vm.Activity.ImageList.Count).For (cons => cons.Constant).WithConversion ("CountToConstraintHeight", Constants.HeightActivityImages);
set.Apply ();

The CountToConstraintHeightConverter is pretty simple, it just checks if the value is equal to 0 to return 0 or otherwise the default height value (Constants.HeightActivityImages).

The code gives no execution error and passes through the Converter but when I run the app, the View is still there, empty.

On the other hand if I run the following line of code inside ViewWillLayoutSubviews it works perfectly but it's not binded.

ConstraintHeightPictures.Constant = ViewModel.Activity.ImageList.Count > 0 ? Constants.HeightActivityImages : 0.0f;

Any ideas?

Many thanks in advance!

Jordi

Upvotes: 2

Views: 1022

Answers (1)

Stuart
Stuart

Reputation: 66882

I think the problem is that iOS needs you to call LayoutIfNeeded (or similar) after setting the constant.

e.g. in order to animate a constraint constant change, see Are NSLayoutConstraints animatable?

For binding, you could probably do this using a property on your View like:

public float PicHeight
{
     get { return ConstraintHeightPictures.Constant; }
     set { 
         ConstraintHeightPictures.Constant = value;
         _pictureView.SetNeedsUpdateConstraints();
         UIView.Animate(0.25f, () => {
             _pictureView.LayoutIfNeeded();
         }
     }
}

This could then be bound as:

set.Bind (this).To (vm => vm.Activity.ImageList.Count).For (v => v.PicHeight).WithConversion ("CountToConstraintHeight", Constants.HeightActivityImages);

I think that should work... (and if you don't want animation then it should be easy to strip that out)

Alternatively... you might also be able to build a custom binding that would know how to do this change (although it might be a little complicated by the fact that it would need access to both the child view and the constraint)

Upvotes: 3

Related Questions