Feature: force a relayout/update from script

FlexBuilder is deeply integrated with core Unity and will automatically relayout whenever it needs to. In 95% of cases you won't need to think about this - FlexBuilder and Unity will handle it. But there are still a few cases where the changes can't be detected automatically (typically because Unity is missing the required callbacks) - and there's always the chance of hitting a bug. To handle these cases we have public API calls that will 'force' a relayout to happen.

TreeAlgorithms

FlexBuilder has two pluggable sets of algorithms: the Flexbox algorithm, and the Tree algorithm. The latter is where all relayout activity happens, and relayout requests are interpreted. In general if you want to manually trigger relayout you'll be doing it by calling methods on a Tree algorithm - but some of the common cases have shortcut methods in FlexItem, FlexContainer, and TextMeshPro to save you typing out extra code.

If you want to use the TreeAlgorithm methods directly, or use some of the more precise ones that don't have a convenient shortcut, you'll need to:

  1. Get the RootFlexContainer for your layout (TreeAlgorithms are shared by all children and descendants of an RFC)
  2. Get the TreeAlgorithm reference from your RFC
  3. Cast it to the right interface so you can access the public methods

NB: the final step is only necessary because of backwards compatibility - everything is type-safe and later versions of FlexBuilder add extra options. If you typecase the algorithm to the latest version of the interface you'll be able to access newer methods.

In code that looks like this:

// for a Container:
var myFlexContainer = ...
if( myFlexContainer.sharedTreeAlgorithm is ITreeUpdateAlgorithmV4 algorithmV4 ) // interpret it as a v4+ algorithm
    algorithmV4.FlexPropertyPathModified( this, "bindingPath" );

// for an Item:
var myFlexItem = ...
if( myFlexItem.HasParentContainer( out FlexContainer parentFC ) )
{
   if( parentFC.sharedTreeAlgorithm is ITreeUpdateAlgorithmV4 algorithmV4 )
      algorithmV4.FlexPropertyPathModified( this, bindingPath );
}

Optimized API calls

These calls do the minimum work possible, and are designed for convenience - feel free to use them whenever appropriate.

FlexItem

public void OnContentSizeChanged()

This method is for the 5% of cases where we cannot automatically detect that a single UI element has changed size, because Unity doesn't issue callbacks for the change. For instance if you change the texture/Sprite than an Image is referencing there's no way for us to know that happened - you can call this method on that Image's self (or parent) FlexItem and FlexBuilder will auto-layout.
NB: if you change the text of a TextMeshPro or UI.Text object then I recommend you use 'SetFlexText' instead (see below).

Text / TextMeshPro

public static void SetFlexText( this Text textElementToChange, string newText )
public static void SetFlexText( this TextMeshProUGUI textElementToChange, string newText )

This pair of methods allows you to take any Text/TMP object and call: "myLabel.SetFlexText( "newstring" );" and it will automatically update the text (as if you called: "myLabel.text = "newstring"") and also relayout that text object as necessary.
These methods internally use the 'OnContentSizeChanged()' method above, but for convenience they also update the text string.

NB: in FlexBuilder-2024 we're currently trying to make this automatic for TextMeshPro objects, but this is still experimental. Until that succeeds, you need to either use the OnContentSize

Aggressive API calls

These calls 'force' a partial or full relayout; these are the safety-net in case normal auto-relayout is failing, or when you suspect it's failing and want to see what happens if you force it to happen. These should only be used when absolutely necessary - there's no harm, but they tend to be a bit slower than the more precisely targetted methods listed earlier.

ITreeUpdateAlgorithmV4

public abstract void ForceRelayoutFullTree( RootFlexContainer rfc, string purpose )

This method forces the entire flexbox tree (starting at the RootFlexContainer and moving downwards) to relayout. This is the most expensive layout you can do: everything will get recalculated. If you find yourself needing this method then you've probably found a bug in FlexBuilder - please report it in Discord or to our Support address.

NB: for usage info, see the comments at top of this post.

NB: there are many other methods in this interface that give you finer control over forcing relayouts - each one is described in the class documentation with some info on when/why it gets called. If you need to relayout the full tree, it's worth trying some of the other methods too in case you can do a smaller/narrower relayout and achieve the same result.

Low-level targeted API calls

Internally many of FlexBuilder's methods use these API calls. If you want to do lower-level code/customization you will probably need to call these too (e.g. if you write your own custom Unity Inspectors for FlexBuilder). They should not be necessary for relayout, but they are an easy/convenient way to force or test relayout in the same way that the Unity inspector triggers it.

FlexContainer

public virtual void OnFlexPropertyModified(string propertyName)

This method is the same one that is automatically invoked internally whenever a property changes - e.g. if you change the margin, paddings, or if you change the flex-direction. The propertyName argument is optional, but some properties will generate special-case code that is more optimized, so if you have changed a specific property (e.g. "cssPadding.right") then it's worth passing the name in here.

public void OnFlexPropertyPathModified( string bindingPath )

This method is the same one that is automatically invoked internally whenever a property changes - e.g. if you change the margin, paddings, or if you change the flex-direction. The propertyName argument is optional, but some properties will generate special-case code that is more optimized, so if you have changed a specific property (e.g. "cssPadding.right") then it's worth passing the name in here.