Difficulty: EXPERT
With each release of Flexbox4Unity, you get multiple free layout algorithms. Usually you want to use the latest one. For most people, this is all they’ll need.
But if you want to customise Flexbox – if you want to add other CSS features to UnityUI, or you want to integrate it more tightly with your own app/game code – what do you do?
You could modify the source line by line, but there’s an easier way. Flexbox4Unity has fully hot-swappable Modular Layout Algorithms. You can swap back and forth between algorithms and see the differences in realtime right in the UnityEditor.
Step 1: Subclass IFlexboxLayoutAlgorithm
IFlexboxLayoutAlgorithm is named using C# interface syntax, because we treat it like an interface. But Unity doesn’t support interfaces in the Editor, so this has to be a class.
There are only three methods you need to implement (and two of those I can give you copy/paste starting code for):
- public abstract string defaultAssetName { get; }
- public abstract bool isLayoutInProgress { get; }
- public abstract void Layout(FlexContainer fc);
Step 2: Implement “defaultAssetName”
This is used by the Inspector to do the “auto upgrade to latest” algorithm. You don’t need to return anything here. Feel free to implement this as:
public override string defaultAssetName { get { return "My New Layout Algorithm"; } }
Step 3: Implement “isLayoutInProgress”
This is more tricky: to integrate seamlessly with UnityUI, I had to do a lot of tricks, and discover a lot about the internals of the UnityEngine and Editor. There are multiple places where the UnityEngine can trigger a recursive call to layout, if we’re not careful.
So, built-in to Flexbox4Unity, during layout there are several places where the asset behaves differently if a layout is already happening in memory. This prevents infinite loops and editor crashes when you make a mistake. It also increases performance by avoiding work that isn’t necessary, and re-using partial results.
But it needs your algorithm to keep track of whether a layout is currently happening or not. Feel free to use the implementation I have in the main official algorithms:
private int _layoutsStartedUnfinished = 0; public void OnEnable() { _layoutsStartedUnfinished = 0; } public override void Layout(FlexContainer fc) { _layoutsStartedUnfinished++; try { LayoutInternal(fc); } finally { _layoutsStartedUnfinished--; } } private void LayoutInternal( FlexContainer fc ) { ... // this is where your custom code goes }
Two very important notes here:
- We reset the number of layouts in OnEnable: if you ever crash your Editor, or your laptop runs out of battery, etc … the counter may get out of sync. This reset makes sure that the layouts always reset whenever Unity restarts, or you exit/enter play mode.
- We use try/finally to make sure that – even if there’s a bug in your layout code – the number of layours is always correctly increased/decreased. Even if you get a NullReferneceException because of a mistake in your code, Flexbox4Unity will auto-recover and keep doing layouts correctly.
Step 4: Write your custom layout code!
If you followed step 2 above, you now have an empty layout method “LayoutInternal( FlexContainer )” to fill in with your custom layout engine.
It only takes one argument – the FlexContainer to layout – and it only has to do three things
- Decide the size/shape of every direct child element
- Decide the position of every direct child element
- Call the UnityUI methods on each child’s RectTransform to apply the new size and position
NOTE: you DO NOT need to recurse to all grandchildren and descendents – Flexbox4Unity will do this for you automatically! It has an in-built seto of performance optimizations (which make it much faster than Unity’s official layout system), which intelligentlly decide when your layout algorithm needs to be recursed and when it doesn’t.
In short: if you change the size of an item, Flexbox4Unity will – sooner or later (usually within the same frame) – come back and invoke your algorithm a second time, this time on the item you resized. But if you reposition an item without changing the size, Flexbox4Unity will detect that the size is the same, so there’s no need to recalculate, and avoid the unnecessary work. It is slightly more complex than this, because it detects situations where the internal size of the item MIGHT have changed – but that is currently not exposed to the layout algorithm.
If you write your own layout algorithm and need to modify the above behaviour, please get in touch with me via the forums or email, and I will work with you to give you more control over the performance optimizer. But for 99% of cases, you shouldn’t need to touch it.
Now go write your custom algorithm!