Namespace NinjaTools.FlexBuilder
Classes
BFlexComponent
The absolute minimum possible set of shared behaviour between FlexItem and FlexContainer.
(NB: FlexBuilder versions 0.1-2.0 had this class, but in reality the ideal is that they share ZERO code; v4 reinstated this for a very small number of features that really must be shared between them and shouldn't be accessed by external classes - because C# is so bad at permissions/privacy, this was the only way to give them a SHARED set of private internal methods and helper-classes)
CompileTimeConstants
FlexBuilder's central class for the global constants that are used throughout the project, especially "current version" and URLs for the latest live docs etc.
You should never need to access this data directly (unless you need to add custom behaviour based on a specific version number of FlexBuilder)
CreateFlexComponents
Quick methods for creating new FlexItems and FlexContainers directly from script, with automatic Undo support, correct automatic setup/config, etc.
CSSHelpers
Methods that are frequently needed to help implement common CSS3 features - TODO: this may get merged into one of the ILayoutAlgorithm-base-classes in future
EditorForFlexContainerGizmoRenderer
FlexContainer
Flexbox implementation as per CSS3 (https://www.w3.org/TR/css-flexbox-1/#box-model): the FlexContainer holds 0 or more child FlexItems, and arranges them according to the Flexbox layout settings. Child FlexItems can also be FlexContainers themselves, in which case each child will layout its own children.
Note: a FlexContainer will not perform any layout unless it is part of a RootFlexContainer.
Generally you create a layout by doing the following steps:
- Choose a RootFlexContainer or FlexContainer you've already configured
- Add a new child with both a FlexItem (to control how the parent RFC/FC lays it out) and a FlexContainer (for you to apply new layout settings)
- Add to your new FlexContainer as many child objects as you need, with a FlexItem on each
- Choose the layout settings on your new FlexContainer
Creating from script
Recommended to use CreateFlexComponents which simplifies the creation/adding of new instances
Sizing
FlexContainers do not have any control over their own size: they require an attached FlexItem, and a parent FlexContainer (or RootFlexContainer) - the parent then decides what size this FlexContainer should be.
Sizing and Positioning children
FlexContainers perform all the sizing AND positioning of their direct children. Only children with a FlexItem component are affected - all others are ignored. If you remove the FlexItem from a child it will become effectively invisible to Flexbox and will only be sized by Unity's in-built UI (if at all).
The FlexContainer uses its local LayoutAlgorithm to perform the actual layout. The local LayoutAlgorithm is currently set by the first parent RootFlexContainer, and all FlexContainers embedded in that RootFlexContainer share the same LayoutAlgorithm.
CSS3 Settings
The primary settings from the CSS3/Flexbox specification that control layout of a FlexContainer are:
FlexContainerEvent
Unity's system allowing for events and listeners
FlexItem
Flexbox implementation as per CSS3 (https://www.w3.org/TR/css-flexbox-1/#box-model): "... children of a flex container are called flex items and are laid out using the flex layout model."
Each UI element in your UI requires a FlexItem for it to be layed out; Flexbox does not understand UnityUI, it only understands FlexItems and FlexContainers.
Note: A FlexItem has no effect unless its parent object is a FlexContainer or RootFlexContainer - the FlexContainers perform all the actual layout.
When assigning FlexItems to UI elements you have a choice: you can either attach a FlexItem directly onto the UI element (Button, Label, etc), or you can create an empty GameObject, attach the FlexItem to that object, and then add your UI element as a child of this empty GameObject - FlexItem is designed to intelligently detect both situations and adapt accordingly.
Typically you layout UI items in a FlexContainer with these steps:
- Choose a FlexContainer you've already configured
- Add all the child UI elements you require (eg Buttons, Labels, TextFields, etc)
- For each child UI element: attach a FlexItem to that child, and configure it
Creating from script
Recommended to use CreateFlexComponents which simplifies the creation/adding of new instances
Sizing
FlexItem has a large amount of intelligent / heuristic code for auto-sizing and auto-detecting the content of your UI. In Unity, FlexBuilder uses all the information it can to establish the correct size 'by default', and in most cases you don't need to hand-configure the FlexItem settings. The default Flexbox size is 'AUTO', which generally resolves as 'CONTENT' (although see cssWidth and cssHeight), but you can override this at any time by setting the FlexItem's flexBasis to e.g 'LENGTH' and setting a fixed size in pixels.
When the size has been set to 'CONTENT', your current LayoutAlgorithm will use its own internal metrics to decide what the "natural content size" is. Generally this will use classes from NinjaTools.FlexBuilder.ContentSizing.
Positioning
All positioning of FlexItems is handled by their parent FlexContainer.
Reacting to content-changes / Auto re-sizing
Since version 4.0, FlexBuilder is able to auto-detect all changes - both in Editor and in Player - to Flexbox settings that invalidate the layout, and intelligently triggers a relayout immediately.
However: there are situations that only Unity can detect, and they don't provide a mechanism for non-Unity applications or features to respond to them. The most common example is: changing the content of a Text component.
In those cases you may need to manually inform FlexBuilder that Unity has done something that invalidates the auto-calculated content size. This is not necessarily needed: if your FlexItem had a fixed cssWidth AND a fixed cssHeight, then changing the content will have no effect (FlexBuilder wasn't using the content's size to size the FlexItem).
If it is needed, use the method ContentSizePossiblyChanged() to inform FlexBuilder.
CSS3 Settings
The primary settings from the CSS3/Flexbox specification that control size and position of a FlexItem are:
FlexItem.BoxSizes
EXPERIMENTAL: Currently only used for the CalculateBoxSizesIfResolved() method, future versions will likely promote this to a standalone file if it proves useful.
NOTE: for setting a RectTransform.size, FlexBuilder ALWAYS uses the ContentBox size (this is an intrinsict requirement of integrating with Unity's rendering system, indpendent of the BoxMode of the FlexItem)
FloatEnum<T>
Workaround for Unity's lack of direct support for compound-type fields as primary fields in MonoBehaviors. Don't use this unless you know what you are doing (it's required by Unity if you're going to use PropertyField and SerializedProperty, but those are very hard to use correctly).
RootFlexContainer
Special FlexContainer that sits at the top-level of all FlexBuilder layouts and contains semi-global settings that control how the Flexbox layout integrates with the local UnityUI/RectTransform layout. You cannot use Flexbox without having at least one RootFlexContainer on your Canvas.
Each flexbox layout has a single RootFlexContainer: layout is applied specificaly to 'all descendent FlexContainers and FlexItems of the RootFlexContainer'.
You can have multiply RootFlexContainers on a single Canvas - each one will perform its layout separately and independently, and will ignore the others.
Creating from script
Recommended to use CreateFlexComponents which simplifies the creation/adding of new instances
SizeMode: standalone? or scrollview?
Most RFCs use a sizeMode of 'UNITY_UI': this means the RFC itself is sized by the RectTransform, 100% controlled by Unity. The RFC then sizes and positions all its children and descendents ignoring RectTransform but using Flexbox instead.
However: scrollviews / scrollrects need to dynamically auto-resize themselves based on their (changing) contents. For those situations, the RFC needs to be placed in a sizeMode of 'FIT_CONTENT', which resizes the RFC after every relayout to make it precisely fit its content.
FIT_CONTENT is also sometimes useful in advanced / complex layouts, but is only fully supported for scrollviews.
LayoutAlgorithms
Each RFC can have a unique LayoutAlgorithm instance (NOTE: prior to v4.0, all RFC's had to share the same LayoutAlgorithm). The LayoutAlgorithm provides 99% of the implementation of Flexbox, and you can drag/drop different algorithm implementations onto your RFC in the Inspector to change which one it uses.
For most projects you'll always want to use the 'most recently released' LayoutAlgorithm - and the RFC's inspector will automatically prompt you if it detects you're using an out-dated LayoutAlgorithm.
However: new LayoutAlgorithms sometimes fix bugs in old ones that you might be relying on for your game UI (ie. you already accounted for the bug when creating your UI) - in that case, upgrading would force you to go back and re-do potentially many parts of your UI. In those cases you may wish to keep your RFC using the original LayoutAlgorithm, while using the new LayoutAlgorithm for new RFCs you create going forwards.
Differences between RootFlexContainer and FlexContainer
- FlexContainers cannot perform layout unless one of their ancestors is a RootFlexContainer
- ... RootFlexContainers always perform layout for themselves and all their descendents.
- FlexContainers should always have an attached FlexItem (to allow them to be embedded in a FlexContainer/RootFlexContainer)
- ... RootFlexContainers MUST NOT have an attached FlexItem (since they cannot be embedded in anything)
- RootFlexContainers hold 'shared' settings for all the FlexContainers/FlexItems in the layout
- RootFlexContainers control which LayoutAlgorithm is used for all their descendents
Embedding RootFlexContainers inside RootFlexContainers
When performing layout on a RootFlexContainer, it will process all child FlexItems, and for each one that has a FlexContainer attached: also all (grand)child FlexItems of the (child)FlexContainer. This is then processed recursively on all descendent GameObjects.
This continues down the tree until a FlexItem is found that has no FlexItem children OR has a RootFlexContainer attached. (NOTE: v4.x does not currently allow the RootFlexContainer to be attached directly to a FlexItem; you need instead to insert a 'dummy' gameobject between the two, and use RectTransform settings to make the dummy object expand to fill the parent FlexItem. You can then place the RootFlexContainer as the sole child of this dummy object).
This allows you to embed a second RootFlexContainer (RFC) inside a first. This is rarely used in normal situations, but is common when putting scrollviews / scrollable content inside a flexbox layout: Unity requires us to separate the 'scrollable' content into a separate sublayout, and the secondary RFC provides that.
ValidatorProject
Project-level auto-fix features that have to be invoked from Runtime classes, so cannot be placed in the .Editor namespaces
WorkaroundUnityMissingGetComponentMethods
Adds some frequently used methods that Unity should have implemented for GetComponent, that make it much more accurate/effective.
WorkaroundUnityRectTransformSetSize
Used heavily in Flexbox: Unity engineers never implemented 'SetSize' for RectTransform
Interfaces
IFlexComponent
Common features of FlexItem and FlexContainer that are needed universally: their fully-qualified names. This also allows code to be written that accepts either a FlexItem or FlexContainer, and doesn't care which.
Enums
BFlexComponent.GizmosRenderMode
Lets us render Gizmos in Unity scene view different ways - TODO: will be removed/replaced with a more powerful gizmos-rendering subsystem
RootContainerSizeMode
See the class description for RootFlexContainer for more info - changes whether the RFC sizes itself, is sized by UnityUI/RectTransform, or some combination of both.