CaffeinatedLayout
public protocol CaffeinatedLayout
-
Declaration
Swift
typealias Subelements = LayoutSubelements
-
Cached values associated with the layout instance.
If you create a cache for your custom layout, you can use a type alias to define this type as your data storage type. Alternatively, you can refer to the data storage type directly in all the places where you work with the cache.
See
makeCache(subelements:environment:)
for more information.Declaration
Swift
associatedtype Cache = Void
-
Returns the size of the composite element, given a proposed size constraint and the container’s subelements.
Implement this method to tell your custom layout container’s parent how much space the container needs for a set of subelements, given a size constraint. The parent might call this method more than once during a layout pass with different proposed sizes to test the flexibility of the container.
In Blueprint, parents ultimately choose the size of their children, so the actual size that this container is laid out in may not be a size that was returned from this method.
Sizing Rules
For performance reasons, the layout engine may deduce the measurement of your container for some constraint values without explicitly calling
sizeThatFits(proposal:subelements:environment:cache:)
. To ensure that the deduced value is correct, your layout must follow some ground rules:- Given one fixed constraint axis, the element’s growth along the other axis should be monotonic. That is, an element can grow when given a larger constraint, or shrink when given a smaller constraint, but it should never shrink when given a larger constraint. When growing on one axis, it is OK to shrink along the other axis, such as a block of text that re-flows as the width changes.
- For a constraint axis value a, if an element has a length b that is less than a on
that axis, then the element must return b for all constraint values between a and
b. In other words, growth must follow a stair-step pattern; elements that grow
continuously by calculating a fixed inset of the constraint or a percentage value of the
constraint are forbidden. For example, if an element returns
10
for a constraint of20
, then the element must return10
for all values in the range[10, 20]
. - If your element has no intrinsic size along an axis, you can represent that in a couple
ways:
- You can return a fixed value representing the minimum size for your element. In this approach, a containing element is usually responsible for stretching your element to fill desired space.
- You can return a size that entirely fills the constraint proposed. In this approach,
you must return
.infinity
when the constraint isunconstrained
. Otherwise, your behavior would be in violation of rule #1.
If an element does not adhere to these rules, it may lay out in unexpected and unpredictable ways.
Declaration
Swift
func sizeThatFits( proposal: SizeConstraint, subelements: Subelements, environment: Environment, cache: inout Cache ) -> CGSize
Parameters
proposal
A size constraint for the container. The container’s parent element that calls this method might call the method more than once with different constraints to learn more about the container’s flexibility before choosing a size for placement.
subelements
A collection of proxies that represent the elements that the container arranges. You can use the proxies in the collection to get information about the subelements as you determine how much space the container needs to display them.
environment
The environment of the container. You can use properties from the environment when calculating the size of this container, as long as you adhere to the sizing rules.
cache
Optional storage for calculated data that you can share among the methods of your custom layout container. See
makeCache(subelements:environment:)
for details.Return Value
A size that indicates how much space the container needs to arrange its subelements.
-
Assigns positions to each of the layout’s subelements.
Blueprint calls your implementation of this method to tell your custom layout container to place its subelements. From this method, call the
place(at:anchor:size:)
method on each item insubelements
to tell the subelements where to appear in the user interface.You can also update the
attributes
property of each subelement to set properties like opacity and transforms on each subelement.Be sure that you use computations during placement that are consistent with those in your implementation of other protocol methods for a given set of inputs. For example, if you add spacing during placement, make sure your implementation of
sizeThatFits(proposal:subelements:environment:cache:)
accounts for the extra space.Declaration
Swift
func placeSubelements( in size: CGSize, subelements: Subelements, environment: Environment, cache: inout Cache )
Parameters
size
The region that the container’s parent allocates to the container. Place all the container’s subelements within the region. The size of this region may not match any size that was returned from a call to
sizeThatFits(proposal:subelements:environment:cache:)
.subelements
A collection of proxies that represent the elements that the container arranges. Use the proxies in the collection to get information about the subelements and to tell the subelements where to appear.
environment
The environment of this container. You can use properties from the environment to vary the placement of subelements.
cache
Optional storage for calculated data that you can share among the methods of your custom layout container. See
makeCache(subelements:environment:)
for details. -
Creates and initializes a cache for a layout instance.
You can optionally use a cache to preserve calculated values across calls to a layout container’s methods. Many layout types don’t need a cache, because Blueprint automatically caches the results of calls into layout methods, such as
sizeThatFits(_:)
. Rely on the protocol’s default implementation of this method if you don’t need a cache.However you might find a cache useful when the layout container repeats complex intermediate calculations across calls to
sizeThatFits(proposal:subelements:environment:cache:)
andplaceSubelements(in:subelements:environment:cache:)
. You might be able to improve performance by calculating values once and storing them in a cache.Note
A cache’s lifetime is limited to a single render pass, so you cannot use it to store values across multiple calls toplaceSubelements(in:subelements:environment:cache:)
. A render pass includes zero, one, or many calls tosizeThatFits(proposal:subelements:environment:cache:)
, followed by a single call toplaceSubelements(in:subelements:environment:cache:)
.Only implement a cache if profiling shows that it improves performance.
Initializing a cache
Implement the
makeCache(subelements:)
method to create a cache. You can add computed values to the cache right away, using information from the subelements input parameter, or you can do that later. The methods of theLayout
protocol that can access the cache take the cache as an in-out parameter, which enables you to modify the cache anywhere that you can read it.You can use any storage type that makes sense for your layout algorithm, but be sure that you only store data that you derive from the layout and its subelements (lazily, if possible). For this to work correctly, Blueprint needs to be able to call this method to recreate the cache without changing the layout result.
When you return a cache from this method, you implicitly define a type for your cache. Be sure to either make the type of the cache parameters on your other
Layout
protocol methods match, or use a type alias to define theCache
associated type.Declaration
Swift
func makeCache(subelements: Subelements, environment: Environment) -> Cache
Parameters
subelements
A collection of proxy instances that represent the subelements that the container arranges. You can use the proxies in the collection to get information about the subelements as you calculate values to store in the cache.
environment
The environment of this container.
Return Value
Storage for calculated data that you share among the methods of your custom layout container.