# How bindingViews and lazyBindingViews Synchronize Views with a Target View's Frame in FrameLayoutKit

> Learn how bindingViews and lazyBindingViews in FrameLayoutKit keep auxiliary views synced with a target view's frame during layoutSubviews. Optimize your layout updates.

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

---

**`bindingViews` and `lazyBindingViews` automatically synchronize the frames of auxiliary views to match a target view's dimensions by evaluating a static array or dynamic closure during every `layoutSubviews()` pass.**

FrameLayoutKit provides a powerful mechanism to keep multiple views visually aligned with a primary target view. Through the `bindingViews`, `lazyBindingViews`, and `bindingEdgeInsets` properties, the library ensures that dependent views automatically resize and reposition whenever the target view's frame changes. This synchronization happens in real-time during the layout cycle, creating a "live mirror" effect without manual frame calculations.

## Understanding the Binding Properties

FrameLayout exposes three key properties in [`FrameLayoutKit/Classes/FrameLayout.swift`](https://github.com/kennic/framelayoutkit/blob/main/FrameLayoutKit/Classes/FrameLayout.swift) that control view synchronization:

| Property | Type | Purpose |
|----------|------|---------|
| `bindingViews` | `[UIView]?` | A static array of views bound to the target view during every layout pass. |
| `bindingEdgeInsets` | `UIEdgeInsets` | Insets applied to the target view's frame before copying to bound views. |
| `lazyBindingViews` | `(() -> [UIView?]?)?` | A closure evaluated on every layout pass, enabling dynamic view binding. |

The `bindingEdgeInsets` property allows you to create padding effects. For example, setting `UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)` causes bound views to be 10 points smaller on each side than the target view.

## How Frame Synchronization Works

The synchronization mechanism triggers automatically during the view layout cycle. In [`FrameLayout.swift`](https://github.com/kennic/framelayoutkit/blob/main/FrameLayout.swift) (lines 75-95), the `layoutSubviews()` method finishes positioning the `targetView` and then invokes:

```swift
bindViews(to: targetView)

```

The `bindViews(to:)` implementation performs three critical steps:

### 1. Collect Views to Bind

```swift
var bindViews = bindingViews ?? []
if let views = lazyBindingViews?() { 
    bindViews.append(contentsOf: views.compactMap { $0 }) 
}

```

This merges the static `bindingViews` array with the dynamic results from `lazyBindingViews`. The closure is executed on every layout pass, allowing runtime changes to the bound view set.

### 2. Compute the Source Frame

```swift
let targetFrame = targetView.frame.inset(by: bindingEdgeInsets)

```

The target view's current frame is adjusted by the specified insets. This computed rectangle serves as the source of truth for all bound views.

### 3. Copy Frame to Bound Views

The implementation handles three hierarchy scenarios:

- **Same superview**: Sets frame to `(0,0,size)` relative to shared parent
- **Different superviews**: Converts the frame from target's superview to bound view's superview using coordinate conversion
- **Direct assignment**: Uses the frame directly when no conversion is needed

This ensures bound views occupy the same **visual rectangle** as the target view, regardless of their position in the view hierarchy.

## Static vs Dynamic Binding

FrameLayoutKit offers two approaches depending on whether your bound views are fixed or change at runtime.

### Static Binding with bindingViews

Use `bindingViews` when you know at initialization which views must synchronize:

```swift
let avatar = UIImageView(image: UIImage(named: "avatar"))
let nameLabel = UILabel()
let profileLayout = FrameLayout(targetView: avatar)

// Keep the label sized exactly like the avatar
profileLayout.bindingViews = [nameLabel]
profileLayout.bindingEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

```

### Dynamic Binding with lazyBindingViews

Use `lazyBindingViews` when the set of views changes based on state or user interaction:

```swift
var hintViews: [UILabel] = []

let hintLayout = FrameLayout(targetView: avatar)
hintLayout.lazyBindingViews = { [weak hintLayout] in
    // The closure is executed on each layout pass
    return hintViews.map { $0 as UIView? }
}

// Later you can add/remove hints and the layout will update automatically
let hint = UILabel()
hint.text = "Tap the avatar"
hintViews.append(hint)

```

The closure-based approach ensures that adding or removing views from `hintViews` automatically reflects in the next layout cycle without reconfiguring the FrameLayout instance.

## Practical Implementation Examples

### Chainable Configuration

FrameLayoutKit supports chainable setters via `FrameLayout+Chainable.swift`:

```swift
let layout = FrameLayout(targetView: imageView)
    .bindingViews([overlayView, shadowView])
    .bindingEdgeInsets(UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4))

```

### Coordinate Space Conversion

When bound views exist in different superviews, FrameLayout automatically handles conversion. This is particularly useful in complex hierarchies:

```swift
// targetView is in containerA
// badgeView is in containerB (sibling of containerA)
let frameLayout = FrameLayout(targetView: targetView)
frameLayout.bindingViews = [badgeView]
// FrameLayout converts coordinates between containerA and containerB automatically

```

## Summary

- **`bindingViews`** provides static array-based synchronization for fixed sets of views.
- **`lazyBindingViews`** enables dynamic runtime binding through a closure evaluated on every layout pass.
- **`bindingEdgeInsets`** allows padding adjustments before frame copying.
- The synchronization occurs in `bindViews(to:)` called from `layoutSubviews()` in [`FrameLayout.swift`](https://github.com/kennic/framelayoutkit/blob/main/FrameLayout.swift).
- FrameLayout handles same-superview and different-superview scenarios automatically through coordinate conversion.

## Frequently Asked Questions

### What is the difference between bindingViews and lazyBindingViews?

`bindingViews` accepts a static array of `UIView` objects that remains constant unless you manually reassign the property. `lazyBindingViews` accepts a closure that returns an array of optional views and executes during every `layoutSubviews()` cycle. Use `bindingViews` for fixed relationships and `lazyBindingViews` when the set of bound views changes dynamically based on application state.

### How do bindingEdgeInsets affect the synchronized frame?

The `bindingEdgeInsets` property insets the target view's frame before copying it to bound views. For example, setting `UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)` creates a 10-point padding, causing bound views to be smaller than the target view by 20 points in both dimensions (10 on each side). This allows bound views to act as borders, backgrounds, or inset overlays.

### Does FrameLayoutKit handle views in different superviews?

Yes. During the `bindViews(to:)` execution, FrameLayoutKit checks whether the bound view shares the same superview as the target view. If the superviews differ, the implementation converts the target frame from the target's coordinate space to the bound view's coordinate space using UIKit's coordinate conversion methods. This ensures bound views occupy the same visual rectangle regardless of their position in the view hierarchy.

### When should I use lazyBindingViews over bindingViews?

Use `lazyBindingViews` when the set of views requiring synchronization is not known at initialization time or changes during the view's lifecycle. Common scenarios include: dynamically adding hint labels based on user interaction, binding to views created in response to data changes, or managing views that may be nil or deallocated and recreated. The closure-based approach ensures FrameLayoutKit evaluates the current state on every layout pass without requiring manual property updates.