How to Implement Overlapping Views in FrameLayoutKit: ZStackLayout vs isOverlapped Property
ZStackLayout forces overlapping behavior by default, while the isOverlapped property lets you toggle overlap mode on any existing StackFrameLayout subclass using the chainable overlapped(_:) method.
FrameLayoutKit provides two distinct approaches for creating overlapping views in iOS and macOS applications. Whether you need a dedicated Z-stack container or want to enable overlap on an existing horizontal or vertical stack, understanding the difference between ZStackLayout and the isOverlapped property is essential for building layered user interfaces.
Understanding the Overlapping Views Architecture
The isOverlapped Flag
Located in FrameLayoutKit/Classes/StackFrameLayout.swift at line 22, the isOverlapped property is defined as:
public var isOverlapped: Bool = false { didSet { setNeedsLayout() } }
When set to true, the layout engine treats every child as occupying the full container dimensions. The sizeThatFits and layoutSubviews methods check this flag (visible at line 19 in sizeThatFits, lines 20-23 in the vertical branch, and lines 21-23 in the horizontal branch) and skip normal stacking calculations, aligning each subview to the container's origin.
ZStackLayout Implementation
The ZStackLayout class, found at lines 96-100 in FrameLayoutKit/Classes/StackFrameLayout.swift, is a concrete subclass that hardcodes overlapping behavior:
public class ZStackLayout: StackFrameLayout {
public override init() {
super.init()
axis = .vertical
isOverlapped = true
}
}
Additionally, its overridden add(_:) method at lines 16-18 automatically makes each child flexible by calling super.add(view).flexible(), ensuring children stretch to fill the available space.
Implementing Overlapping Views with ZStackLayout
For simple overlapping scenarios, use the ZStackLayout or its DSL wrapper ZStackView:
// ZStackView is a DSL wrapper around ZStackLayout
let overlapping = ZStackView {
UILabel() // first child – placed at origin
UIImageView(image: img) // second child – drawn on top of the label
UIButton(type: .system) // third child – topmost layer
}
Under the hood, ZStackView inherits from ZStackLayout, which forces isOverlapped = true during initialization. The DSL builder calls the overridden add(_:) method, making every child flexible so they all share the same frame dimensions. Because overlapping is enabled, the layout engine skips spacing calculations and positions each child at the container's origin, creating the classic Z-order stacking effect where later children render on top of earlier ones.
Enabling Overlap on Existing Stacks with isOverlapped
If you already use HStackLayout or VStackLayout and need to toggle overlapping behavior, set the isOverlapped property directly:
let overlappedH = HStackLayout()
.overlapped(true) // chainable setter
.add(UILabel())
.add(UIImageView(image: img))
.add(UIButton(type: .system))
The overlapped(_:) method, defined at line 28 in FrameLayoutKit/Classes/Extensions/StackFrameLayout+Chainable.swift, provides a fluent interface:
@discardableResult public func overlapped(_ value: Bool) -> Self {
self.isOverlapped = value
return self
}
Unlike ZStackLayout, enabling isOverlapped on a standard stack does not automatically make children flexible. You must explicitly call .flexible() on each child if you want them to stretch and fill the container:
stack.add(view).flexible()
If you prefer a DSL-style block, use the generic StackFrameLayout DSL wrapper and set the flag inside the block:
let overlappedV = VStackView {
UILabel()
UIImageView(image: img)
UIButton(type: .system)
}
.overlapped(true) // works because VStackView inherits from StackFrameLayout
When to Use Each Approach for Overlapping Views
Choose the appropriate method based on your architectural requirements:
-
Use
ZStackLayoutwhen you need a dedicated container for overlapping views. It is self-documenting, forces overlap by default, and automatically makes children flexible. Ideal for layered UI elements like badges on icons or background overlays. -
Use
isOverlappedwhen you need to toggle overlapping behavior dynamically on an existingHStackLayoutorVStackLayout. This avoids refactoring your layout hierarchy and allows runtime switching between stacked and overlapped arrangements. -
Combine approaches by nesting a
ZStackLayoutinside a normal stack to isolate overlapping regions within a larger non-overlapping layout.
Key Source Files and Implementation Details
Understanding the implementation helps debug layout issues:
| File | Key Implementation |
|---|---|
FrameLayoutKit/Classes/StackFrameLayout.swift |
Defines isOverlapped at line 22 with didSet { setNeedsLayout() }. Contains ZStackLayout subclass at lines 96-100 and the flexible add(_:) override at lines 16-18. |
FrameLayoutKit/Classes/StackFrameLayout.swift |
Layout logic branches for isOverlapped in sizeThatFits (line 19) and layoutSubviews (vertical branch lines 20-23, horizontal branch lines 21-23). |
FrameLayoutKit/Classes/Extensions/StackFrameLayout+Chainable.swift |
Provides overlapped(_:) at line 28 for fluent API usage. |
Both approaches rely on the same underlying engine: when isOverlapped is true, the layout skips spacing calculations and positions each child at the container's origin, creating the overlapping effect.
Summary
ZStackLayoutprovides a purpose-built solution for overlapping views, automatically settingisOverlapped = trueand making all children flexible.isOverlappedis a boolean flag available on allStackFrameLayoutsubclasses that toggles overlap mode, accessible via the chainableoverlapped(_:)method.- When
isOverlappedis enabled, the layout engine treats every child as occupying the full container frame, skipping normal stacking calculations. - Choose
ZStackLayoutfor dedicated Z-axis containers; useisOverlappedto dynamically enable overlap on existing horizontal or vertical stacks.
Frequently Asked Questions
What is the difference between ZStackLayout and setting isOverlapped on a VStackLayout?
ZStackLayout is a specialized subclass that hardcodes axis = .vertical and isOverlapped = true during initialization, and automatically makes every added child flexible via its overridden add(_:) method. Setting isOverlapped on a VStackLayout only changes the layout behavior to overlap; it does not modify child flexibility or axis settings, giving you more manual control but requiring explicit configuration for each child.
Does enabling isOverlapped affect how children are sized?
Yes. When isOverlapped is true, the layout engine defined in FrameLayoutKit/Classes/StackFrameLayout.swift skips normal stacking mathematics and treats each child as occupying the full container bounds. In ZStackLayout, children are automatically made flexible. When manually enabling isOverlapped on other stacks, you must explicitly call .flexible() on each child if you want them to stretch and fill the container dimensions.
Can I toggle overlapping behavior at runtime?
Yes. Because isOverlapped is defined in FrameLayoutKit/Classes/StackFrameLayout.swift with a didSet observer that calls setNeedsLayout(), you can change its value at any time. The chainable overlapped(_:) method returns Self, allowing you to modify the flag in response to user interactions or state changes, with the layout automatically invalidating and re-rendering on the next layout cycle.
Where is the overlapping logic actually implemented in the source code?
The core logic resides in FrameLayoutKit/Classes/StackFrameLayout.swift. The isOverlapped property is defined at line 22. The layout engine checks this flag in sizeThatFits (around line 19) and layoutSubviews (in both vertical and horizontal branches, lines 20-23 and 21-23 respectively), skipping spacing calculations and aligning children to the container origin when enabled.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →