I've figuratively pulled my hair out on this one. I read from this article "http://gregshackles.com/fluentlayout-2-5/" that FluentLayout now supports constraint editing/removing but it doesn't seem to work on my end. My scenario is to toggle the visibility of a textfield within a UIView when a button is clicked.
I have tried the following.
A. Modifying the height constraint
var height = isVisible ? textfield.Height().EqualTo(0) : textfield.WithSameHeight(textfieldContainer).Multiplier(1 / 3);
textfieldContainer.Add(textfield);
textfieldContainer.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
textfieldContainer.AddConstraints(
textfield.WithSameLeft(textfieldContainer).Plus(12),
textfield.WithSameTop(textfieldContainer).Plus(24),
textfield.WithSameWidth(textfieldContainer),
height
);
B. Using SetActive(false) - Tried this out of desperation
textfieldContainer.Add(textfield);
textfieldContainer.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
textfieldContainer.AddConstraints(
textfield.WithSameLeft(textfieldContainer).Plus(12).SetActive(!isVisible),
textfield.WithSameTop(textfieldContainer).Plus(24).SetActive(!isVisible),
textfield.WithSameWidth(textfieldContainer).SetActive(!isVisible),
textfield.WithSameHeight(textfieldContainer).WithMultiplier(1 / 4).SetActive(!isVisible)
);
Expected outcome
The textfield should be visible depending on the visibility
Actual outcome
The textfield's height never changes, thus it is always visible
My guess is that your height
variable is set once during the page lifecycle, and does not get change after that point. A way of achieving what you need is the following:
Firstly, bind your button click to a command that changes the state of a boolean
on your ViewModel
, so that the boolean
's value changes when the button is clicked:
bindingSet.Bind(yourButton).To(vm => vm.YourCommand);
MvxCommand _yourCommand;
public MvxCommand YourCommand
=> _yourCommand ?? _yourCommand = new MvxCommand(ReverseMyBool);
void ReverseMyBool()
{
YourBoolean = !YourBoolean;
}
If necessary, set YourBoolean
to true during the construction of your ViewModel
, depending on whether your want the field to be hidden during page load. Now that the ViewModel
property holds an accurate true/false state for whether your UITextField
should be hidden, bind the UITextField
itself for Hidden
to the boolean (you may need to use a value converter to reverse the value - if Hidden
is true, the view is invisible):
bindingSet.Bind(textfield).For(c => c.Hidden).To(vm => vm.YourBoolean);
Next, create FluentLayout
variables that relate to both situations (your view being visible and being hidden), and apply both of them:
var textFieldWithOneThirdContainerHeight = textfield.WithSameHeight(textFieldContainer).WithMultiplier(1f /3f);
var textFieldWithZeroHeight = textField.Height().EqualTo(0f);
textfieldContainer.AddConstraints(textFieldWithOneThirdContainerHeight, textFieldWithZeroHeight, /*other constraints here*/);
And finally, bind the constraints for Active
to the boolean
on your ViewModel
- note that one will need to be reversed with a converter:
bindingSet.Bind(textFieldWithOneThirdContainerHeight).For(c => c.Active).To(vm => vm.YourBoolean).WithConversion(new ReverseBooleanValueConverter());
bindingSet.Bind(textFieldWithZeroHeight).For(c => c.Active).To(vm => vm.YourBoolean);
ReverseBooleanValueConverter
would look something like this:
public class ReverseBooleanValueConverter: MvxValueConverter<bool, bool>
{
protected override bool Convert(bool value, Type targetType, object parameter, CultureInfo culture)
=> !value;
}
When YourBoolean
is true, your UITextField
should be invisible, and should have a height of 0f
. When YourBoolean
is false, it should be visible, and should have one third the height of it's container.