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:

    1. 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.
    2. 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 of 20, then the element must return 10 for all values in the range [10, 20].
    3. 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 is unconstrained. 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 in subelements 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:) and placeSubelements(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 to placeSubelements(in:subelements:environment:cache:). A render pass includes zero, one, or many calls to sizeThatFits(proposal:subelements:environment:cache:), followed by a single call to placeSubelements(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 the Layout 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 the Cache 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.