# How the isJustified Property Evenly Distributes Child Views in StackFrameLayout

> Learn how StackFrameLayout's isJustified property evenly distributes child views by calculating and distributing extra space as margins. Fill containers without manual calculations. kennic/framelayoutkit

- Repository: [Nam Kennic/framelayoutkit](https://github.com/kennic/framelayoutkit)
- Tags: deep-dive
- Published: 2026-03-05

---

**Setting `isJustified` to `true` in a `StackFrameLayout` calculates the remaining container space after initial layout and distributes it evenly as extra spacing between visible child views, filling the entire width or height without manual margin calculations.**

The `isJustified` property in the [FrameLayoutKit](https://github.com/kennic/framelayoutkit) library provides automatic space distribution for iOS and macOS layouts. When enabled on a horizontal or vertical stack, it transforms leftover container space into equal gaps between child views, eliminating the need for complex constraint arithmetic in `StackFrameLayout`.

## Understanding the isJustified Property in StackFrameLayout

`StackFrameLayout` supports multiple distribution modes including top, bottom, left, right, equal, split, and center alignment. The `isJustified` property adds a distinct behavior: instead of grouping items at one edge or centering them, it spreads visible children across the entire available axis.

When `isJustified` is enabled, the layout engine performs a three-step algorithm inside the `layoutSubviews()` method. This calculation determines how much extra space to inject between each visible frame, ensuring the first item touches the leading edge and the last item touches the trailing edge.

## How isJustified Calculates Even Distribution

The distribution algorithm implemented in [`StackFrameLayout.swift`](https://github.com/kennic/framelayoutkit/blob/main/StackFrameLayout.swift) follows a precise mathematical sequence to achieve even spacing.

### Step 1: Calculate Remaining Space

After laying out all non-flexible items and applying standard `spacing`, the system determines the leftover container dimension:

```swift
let remainingWidth = containerFrame.width - usedSpace
let numberOfSpaces = numberOfVisibleFrames() - 1

```

For vertical stacks, this calculation uses `remainingHeight` against the container height instead.

### Step 2: Validate the Justification Threshold

Justification only occurs when the leftover space exceeds the `justifyThreshold` property. This prevents micro-adjustments when insufficient space exists:

```swift
if remainingWidth > justifyThreshold, numberOfSpaces > 0 {
    // Proceed with distribution
}

```

### Step 3: Distribute Leftover Space Across Gaps

The algorithm divides the remaining space evenly across the gaps between visible frames. For left-aligned horizontal stacks (`.top` or `.left`), the implementation in [`StackFrameLayout.swift`](https://github.com/kennic/framelayoutkit/blob/main/StackFrameLayout.swift) (lines 995-1014) calculates:

```swift
let extraValuePerSpace = (remainingWidth / CGFloat(numberOfSpaces)) + (spacing / CGFloat(numberOfSpaces))
var index = 1
for frameLayout in frameLayouts where frameLayout != firstFrame {
    var rect = frameLayout.frame
    rect.origin.x += extraValuePerSpace * CGFloat(index)
    frameLayout.frame = rect
    if !frameLayout.isEmpty { index += 1 }
}

```

For right-aligned stacks (`.bottom` or `.right`), the logic at lines 970-1005 applies the same calculation in reverse, subtracting the extra offset from each frame's `origin.x` using an inverted layout array.

Vertical justification follows identical logic but operates on the `y` coordinate within the `else // if axis == .vertical` branch of `layoutSubviews()`.

## Implementation Details in StackFrameLayout.swift

The core justification logic resides in the `layoutSubviews()` method of [`StackFrameLayout.swift`](https://github.com/kennic/framelayoutkit/blob/main/StackFrameLayout.swift). The implementation handles both horizontal and vertical axes through separate code paths that share the same mathematical principles.

Key implementation characteristics include:

- **Left-to-right justification**: Iterates forward through `frameLayouts`, applying progressive offsets to distribute children across the width (lines 995-1014)
- **Right-to-left justification**: Iterates backward through `invertedLayoutArray`, subtracting offsets from the trailing edge inward (lines 970-1005)
- **Vertical axis**: Mirrors the horizontal logic but adjusts `origin.y` instead of `origin.x`

The `isJustified` property is exposed through chainable setters in `Extensions/StackFrameLayout+Chainable.swift`, allowing fluent configuration:

```swift
public func isJustified(_ value: Bool) -> Self {
    self.isJustified = value
    return self
}

```

## Code Examples: Using isJustified in Practice

### Horizontal Stack with Full-Width Distribution

This example creates a horizontal stack where three buttons spread evenly across the entire container width:

```swift
import FrameLayoutKit

let hStack = HStackLayout()
hStack.spacing = 8
hStack.isJustified = true
hStack.add([buttonA, buttonB, buttonC])

parentView.addSubview(hStack)
hStack.frame = parentView.bounds
// Result: First button at left edge, last button at right edge, equal gaps between

```

### Vertical Stack with Justification Threshold

This configuration only applies justification when sufficient vertical space exists, preventing cramped distributions:

```swift
let vStack = VStackLayout()
vStack.isJustified = true
vStack.justifyThreshold = 20  // Minimum 20 points of leftover space required
vStack.spacing = 12
vStack.add([headerLabel, contentView, footerLabel])

parentView.addSubview(vStack)
vStack.frame = CGRect(x: 0, y: 0, width: 300, height: 600)
// Result: Labels and content spread evenly only if height exceeds content + 20pt

```

### Chainable Configuration

Using the fluent API for concise setup:

```swift
let stack = HStackLayout()
    .spacing(16)
    .isJustified(true)
    .justifyThreshold(10)
    .add([view1, view2, view3])

```

## Summary

- The `isJustified` property in `StackFrameLayout` enables automatic even distribution of child views across the full container width or height.
- The algorithm calculates remaining space after standard layout, validates it against `justifyThreshold`, and distributes leftovers evenly across gaps between visible frames.
- Implementation resides in [`StackFrameLayout.swift`](https://github.com/kennic/framelayoutkit/blob/main/StackFrameLayout.swift) within the `layoutSubviews()` method, with separate handling for horizontal (lines 970-1014) and vertical axes.
- The property supports both left-to-right and right-to-left layout directions through forward and inverted array iteration.
- Chainable setters in `StackFrameLayout+Chainable.swift` provide fluent API configuration.

## Frequently Asked Questions

### What is the difference between isJustified and equal distribution in StackFrameLayout?

**Equal distribution** resizes child views themselves to make them identical widths or heights, while **isJustified** maintains each child's intrinsic size and instead adds extra spacing between views to fill the container. Justification preserves content aspect ratios and natural sizes, whereas equal distribution modifies the frames of the child views directly.

### How does the justifyThreshold property affect layout behavior?

The `justifyThreshold` property acts as a minimum space requirement that must be exceeded before justification activates. If the remaining container space after initial layout is less than or equal to `justifyThreshold`, the layout reverts to standard alignment (such as left or top alignment) without distributing extra space. This prevents awkward micro-gaps when insufficient room exists for meaningful distribution.

### Can isJustified be used with vertical stack layouts?

Yes, `isJustified` works identically for both horizontal and vertical axes. When applied to a vertical `StackFrameLayout`, the algorithm calculates `remainingHeight` instead of `remainingWidth` and distributes extra space evenly across the vertical gaps between child views. The implementation handles vertical justification in the `else // if axis == .vertical` branch of the `layoutSubviews()` method using the same mathematical approach as horizontal layouts.

### Does isJustified work with hidden child views?

Yes, the justification algorithm specifically accounts for visibility. The calculation uses `numberOfVisibleFrames()` to determine gap counts and iterates through `frameLayouts` while checking `!frameLayout.isEmpty` before incrementing the distribution index. This ensures that hidden or empty views are excluded from the spacing calculation, and extra space is only distributed between actually visible child views.