One Logo Pool Ball
SwiftUICore · IOS API REFERENCE

AnyLayout

struct · iOS 16.0+ · SDK 27.1

@frozen struct AnyLayout

A type-erased instance of the layout protocol. Use an `AnyLayout` instance to enable dynamically changing the type of a layout container without destroying the state of the subviews. For example, you can create a layout that changes between horizontal and vertical layouts based on the current Dynamic Type setting: struct DynamicLayoutExample: View { @Environment(\.dynamicTypeSize) var dynamicTypeSize var body: some View { let layout = dynamicTypeSize <= .medium ? AnyLayout(HStackLayout()) : AnyLayout(VStackLayout()) layout { Text("First label") Text("Second label") } } } The types that you use with `AnyLayout` must conform to the ``Layout`` protocol. The above example chooses between the ``HStackLayout`` and ``VStackLayout`` types, which are versions of the built-in ``HStack`` and ``VStack`` containers that conform to the protocol. You can also use custom layout types that you define.

Members (10)

method · iOS 16.0+

updateCache

TypeScript
updateCache(cache: AnyLayout_Cache, subviews: LayoutSubviews): { $ret: null; $out: { "cache": AnyLayout_Cache } }
Swift declaration
func updateCache(_ cache: inout AnyLayout.Cache, subviews: AnyLayout.Subviews)

Updates the layout's cache when something changes. If your custom layout container creates a cache by implementing the ``makeCache(subviews:)`` method, SwiftUI calls the update method when your layout or its subviews change, giving you an opportunity to modify or invalidate the contents of the cache. The method's default implementation recreates the cache by calling the ``makeCache(subviews:)`` method, but you can provide your own implementation to take an incremental approach, if appropriate. - Parameters: - cache: Storage for calculated data that you share among the methods of your custom layout container. - subviews: A collection of proxy instances that represent the views arranged by the container. You can use the proxies in the collection to get information about the subviews as you calculate values to store in the cache.

Omit the output parameters from the call. The result contains $ret and $out, with cache inside $out.

method · iOS 16.0+

sizeThatFits

TypeScript
sizeThatFits(proposal: ProposedViewSize, subviews: LayoutSubviews, cache: AnyLayout_Cache): { $ret: { width: number; height: number }; $out: { "cache": AnyLayout_Cache } }
Swift declaration
func sizeThatFits(proposal: ProposedViewSize, subviews: AnyLayout.Subviews, cache: inout AnyLayout.Cache) -> CGSize

Returns the size of the composite view, given a proposed size and the view's subviews. Implement this method to tell your custom layout container's parent view how much space the container needs for a set of subviews, given a size proposal. The parent might call this method more than once during a layout pass with different proposed sizes to test the flexibility of the container, using proposals like: * The ``ProposedViewSize/zero`` proposal; respond with the layout's minimum size. * The ``ProposedViewSize/infinity`` proposal; respond with the layout's maximum size. * The ``ProposedViewSize/unspecified`` proposal; respond with the layout's ideal size. The parent might also choose to test flexibility in one dimension at a time. For example, a horizontal stack might propose a fixed height and an infinite width, and then the same height with a zero width. The following example calculates the size for a basic vertical stack that places views in a column, with no spacing between the views: private struct BasicVStack: Layout { func sizeThatFits( proposal: ProposedViewSize, subviews: Subviews, cache: inout () ) -> CGSize { subviews.reduce(CGSize.zero) { result, subview in let size = subview.sizeThatFits(.unspecified) return CGSize( width: max(result.width, size.width), height: result.height + size.height) } } // This layout also needs a placeSubviews() implementation. } The implementation asks each subview for its ideal size by calling the ``LayoutSubview/sizeThatFits(_:)`` method with an ``ProposedViewSize/unspecified`` proposed size. It then reduces these values into a single size that represents the maximum subview width and the sum of subview heights. Because this example isn't flexible, it ignores its size proposal input and always returns the same value for a given set of subviews. SwiftUI views choose their own size, so the layout engine always uses a value that you return from this method as the actual size of the composite view. That size factors into the construction of the `bounds` input to the ``placeSubviews(in:proposal:subviews:cache:)`` method. - Parameters: - proposal: A size proposal for the container. The container's parent view that calls this method might call the method more than once with different proposals to learn more about the container's flexibility before deciding which proposal to use for placement. - subviews: A collection of proxies that represent the views that the container arranges. You can use the proxies in the collection to get information about the subviews as you determine how much space the container needs to display them. - cache: Optional storage for calculated data that you can share among the methods of your custom layout container. See ``makeCache(subviews:)`` for details. - Returns: A size that indicates how much space the container needs to arrange its subviews.

Omit the output parameters from the call. The result contains $ret and $out, with cache inside $out.

method · iOS 16.0+

placeSubviews

TypeScript
placeSubviews(bounds: { x: number; y: number; width: number; height: number }, proposal: ProposedViewSize, subviews: LayoutSubviews, cache: AnyLayout_Cache): { $ret: null; $out: { "cache": AnyLayout_Cache } }
Swift declaration
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: AnyLayout.Subviews, cache: inout AnyLayout.Cache)

Assigns positions to each of the layout's subviews. SwiftUI calls your implementation of this method to tell your custom layout container to place its subviews. From this method, call the ``LayoutSubview/place(at:anchor:proposal:)`` method on each element in `subviews` to tell the subviews where to appear in the user interface. For example, you can create a basic vertical stack that places views in a column, with views horizontally aligned on their leading edge: struct BasicVStack: Layout { func placeSubviews( in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () ) { var point = bounds.origin for subview in subviews { subview.place(at: point, anchor: .topLeading, proposal: .unspecified) point.y += subview.dimensions(in: .unspecified).height } } // This layout also needs a sizeThatFits() implementation. } The example creates a placement point that starts at the origin of the specified `bounds` input and uses that to place the first subview. It then moves the point in the y dimension by the subview's height, which it reads using the ``LayoutSubview/dimensions(in:)`` method. This prepares the point for the next iteration of the loop. All subview operations use an ``ProposedViewSize/unspecified`` size proposal to indicate that subviews should use and report their ideal size. A more complex layout container might add space between subviews according to their ``LayoutSubview/spacing`` preferences, or a fixed space based on input configuration. For example, you can extend the basic vertical stack's placement method to calculate the preferred distances between adjacent subviews and store the results in an array: let spacing: [CGFloat] = subviews.indices.dropLast().map { index in subviews[index].spacing.distance( to: subviews[index + 1].spacing, along: .vertical) } The spacing's ``ViewSpacing/distance(to:along:)`` method considers the preferences of adjacent views on the edge where they meet. It returns the smallest distance that satisfies both views' preferences for the given edge. For example, if one view prefers at least `2` points on its bottom edge, and the next view prefers at least `8` points on its top edge, the distance method returns `8`, because that's the smallest value that satisfies both preferences. Update the placement calculations to use the spacing values: var point = bounds.origin for (index, subview) in subviews.enumerated() { if index > 0 { point.y += spacing[index - 1] } // Add spacing. subview.place(at: point, anchor: .topLeading, proposal: .unspecified) point.y += subview.dimensions(in: .unspecified).height } 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:subviews:cache:)`` accounts for the extra space. Similarly, if the sizing method returns different values for different size proposals, make sure the placement method responds to its `proposal` input in the same way. - Parameters: - bounds: The region that the container view's parent allocates to the container view, specified in the parent's coordinate space. Place all the container's subviews within the region. The size of this region matches a size that your container previously returned from a call to the ``sizeThatFits(proposal:subviews:cache:)`` method. - proposal: The size proposal from which the container generated the size that the parent used to create the `bounds` parameter. The parent might propose more than one size before calling the placement method, but it always uses one of the proposals and the corresponding returned size when placing the container. - subviews: A collection of proxies that represent the views that the container arranges. Use the proxies in the collection to get information about the subviews and to tell the subviews where to appear. - cache: Optional storage for calculated data that you can share among the methods of your custom layout container. See ``makeCache(subviews:)`` for details.

Omit the output parameters from the call. The result contains $ret and $out, with cache inside $out.

get · iOS 16.0+

animatableData

TypeScript
get animatableData(): AnyLayout_AnimatableData
Swift declaration
var animatableData: AnyLayout.AnimatableData { get set }

The data to animate. SwiftUI reads this property to capture the current vector representation of the animatable state, and writes it back on each animation frame with an interpolated value. The default implementation returns ``EmptyAnimatableData``, meaning nothing is animated. Use the ``Animatable()`` macro to synthesize this property automatically. Implement it by hand only when you need custom interpolation logic such as clamping, normalization, or mapping to a derived value.

set · iOS 16.0+

animatableData

TypeScript
set animatableData(value: AnyLayout_AnimatableData)
Swift declaration
var animatableData: AnyLayout.AnimatableData { get set }

The data to animate. SwiftUI reads this property to capture the current vector representation of the animatable state, and writes it back on each animation frame with an interpolated value. The default implementation returns ``EmptyAnimatableData``, meaning nothing is animated. Use the ``Animatable()`` macro to synthesize this property automatically. Implement it by hand only when you need custom interpolation logic such as clamping, normalization, or mapping to a derived value.

method · iOS 16.0+

explicitAlignment

TypeScript
explicitAlignmentOfInProposalSubviewsCache(guide: HorizontalAlignment, bounds: { x: number; y: number; width: number; height: number }, proposal: ProposedViewSize, subviews: LayoutSubviews, cache: AnyLayout_Cache): { $ret: (number) | null; $out: { "cache": AnyLayout_Cache } }
Swift declaration
func explicitAlignment(of guide: HorizontalAlignment, in bounds: CGRect, proposal: ProposedViewSize, subviews: AnyLayout.Subviews, cache: inout AnyLayout.Cache) -> CGFloat?

Returns the position of the specified horizontal alignment guide along the x axis. Implement this method to return a value for the specified alignment guide of a custom layout container. The value you return affects the placement of the container as a whole, but it doesn't affect how the container arranges subviews relative to one another. You can use this method to put an alignment guide in a nonstandard position. For example, you can indent the container's leading edge alignment guide by 10 points: extension BasicVStack { func explicitAlignment( of guide: HorizontalAlignment, in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () ) -> CGFloat? { if guide == .leading { return bounds.minX + 10 } return nil } } The above example returns `nil` for other guides to indicate that they don't have an explicit value. A guide without an explicit value behaves as it would for any other view. If you don't implement the method, the protocol's default implementation merges the subviews' guides. - Parameters: - guide: The ``HorizontalAlignment`` guide that the method calculates the position of. - bounds: The region that the container view's parent allocates to the container view, specified in the parent's coordinate space. - proposal: A proposed size for the container. - subviews: A collection of proxy instances that represent the views arranged by the container. You can use the proxies in the collection to get information about the subviews as you determine where to place the guide. - cache: Optional storage for calculated data that you can share among the methods of your custom layout container. See ``makeCache(subviews:)`` for details. - Returns: The guide's position relative to the `bounds`. Return `nil` to indicate that the guide doesn't have an explicit value.

Omit the output parameters from the call. The result contains $ret and $out, with cache inside $out.

method · iOS 16.0+

explicitAlignment

TypeScript
explicitAlignmentOfInProposalSubviewsCache662(guide: VerticalAlignment, bounds: { x: number; y: number; width: number; height: number }, proposal: ProposedViewSize, subviews: LayoutSubviews, cache: AnyLayout_Cache): { $ret: (number) | null; $out: { "cache": AnyLayout_Cache } }
Swift declaration
func explicitAlignment(of guide: VerticalAlignment, in bounds: CGRect, proposal: ProposedViewSize, subviews: AnyLayout.Subviews, cache: inout AnyLayout.Cache) -> CGFloat?

Returns the position of the specified vertical alignment guide along the y axis. Implement this method to return a value for the specified alignment guide of a custom layout container. The value you return affects the placement of the container as a whole, but it doesn't affect how the container arranges subviews relative to one another. You can use this method to put an alignment guide in a nonstandard position. For example, you can raise the container's bottom edge alignment guide by 10 points: extension BasicVStack { func explicitAlignment( of guide: VerticalAlignment, in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout () ) -> CGFloat? { if guide == .bottom { return bounds.minY - 10 } return nil } } The above example returns `nil` for other guides to indicate that they don't have an explicit value. A guide without an explicit value behaves as it would for any other view. If you don't implement the method, the protocol's default implementation merges the subviews' guides. - Parameters: - guide: The ``VerticalAlignment`` guide that the method calculates the position of. - bounds: The region that the container view's parent allocates to the container view, specified in the parent's coordinate space. - proposal: A proposed size for the container. - subviews: A collection of proxy instances that represent the views arranged by the container. You can use the proxies in the collection to get information about the subviews as you determine where to place the guide. - cache: Optional storage for calculated data that you can share among the methods of your custom layout container. See ``makeCache(subviews:)`` for details. - Returns: The guide's position relative to the `bounds`. Return `nil` to indicate that the guide doesn't have an explicit value.

Omit the output parameters from the call. The result contains $ret and $out, with cache inside $out.

method · iOS 16.0+

spacing

TypeScript
spacing(subviews: LayoutSubviews, cache: AnyLayout_Cache): { $ret: ViewSpacing; $out: { "cache": AnyLayout_Cache } }
Swift declaration
func spacing(subviews: AnyLayout.Subviews, cache: inout AnyLayout.Cache) -> ViewSpacing

Returns the preferred spacing values of the composite view. Implement this method to provide custom spacing preferences for a layout container. The value you return affects the spacing around the container, but it doesn't affect how the container arranges subviews relative to one another inside the container. Create a custom ``ViewSpacing`` instance for your container by initializing one with default values, and then merging that with spacing instances of certain subviews. For example, if you define a basic vertical stack that places subviews in a column, you could use the spacing preferences of the subview edges that make contact with the container's edges: extension BasicVStack { func spacing(subviews: Subviews, cache: inout ()) -> ViewSpacing { var spacing = ViewSpacing() for index in subviews.indices { var edges: Edge.Set = [.leading, .trailing] if index == 0 { edges.formUnion(.top) } if index == subviews.count - 1 { edges.formUnion(.bottom) } spacing.formUnion(subviews[index].spacing, edges: edges) } return spacing } } In the above example, the first and last subviews contribute to the spacing above and below the container, respectively, while all subviews affect the spacing on the leading and trailing edges. If you don't implement this method, the protocol provides a default implementation that merges the spacing preferences across all subviews on all edges. - Parameters: - subviews: A collection of proxy instances that represent the views that the container arranges. You can use the proxies in the collection to get information about the subviews as you determine how much spacing the container prefers around it. - cache: Optional storage for calculated data that you can share among the methods of your custom layout container. See ``makeCache(subviews:)`` for details. - Returns: A ``ViewSpacing`` instance that describes the preferred spacing around the container view.

Omit the output parameters from the call. The result contains $ret and $out, with cache inside $out.

method · iOS 16.0+

makeCache

TypeScript
makeCache(subviews: LayoutSubviews): AnyLayout_Cache
Swift declaration
func makeCache(subviews: AnyLayout.Subviews) -> AnyLayout.Cache

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 SwiftUI automatically reuses both the results of calls into the layout and the values that the layout reads from its subviews. 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 like ``sizeThatFits(proposal:subviews:cache:)``, ``placeSubviews(in:proposal:subviews:cache:)``, and ``explicitAlignment(of:in:proposal:subviews:cache:)``. You might be able to improve performance by calculating values once and storing them in a cache. - The layout container reads many ``LayoutValueKey`` values from subviews. It might be more efficient to do that once and store the results in the cache, rather than rereading the subviews' values before each layout call. - You want to maintain working storage, like temporary Swift arrays, across calls into the layout, to minimize the number of allocation events. Only implement a cache if profiling shows that it improves performance. ### Initialize a cache Implement the `makeCache(subviews:)` method to create a cache. You can add computed values to the cache right away, using information from the `subviews` 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 subviews (lazily, if possible). For this to work correctly, SwiftUI 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. ### Update the cache If the layout container or any of its subviews change, SwiftUI calls the ``updateCache(_:subviews:)`` method so you can modify or invalidate the contents of the cache. The default implementation of that method calls the `makeCache(subviews:)` method to recreate the cache, but you can provide your own implementation of the update method to take an incremental approach, if appropriate. - Parameters: - subviews: A collection of proxy instances that represent the views that the container arranges. You can use the proxies in the collection to get information about the subviews as you calculate values to store in the cache. - Returns: Storage for calculated data that you share among the methods of your custom layout container.

init · iOS 16.0+

init

TypeScript
static init(layout: SDKHandle): AnyLayout
Swift declaration
init<L>(_ layout: L) where L : Layout

Creates a type-erased value that wraps the specified layout. You can switch between type-erased layouts without losing the state of the subviews.

Skipped declarations

No declarations were skipped in this snapshot.

All SwiftUICore types →