Sample CodeiOS, iPadOS, Mac CatalystReviewed 2026-07-21View on Apple Developer

Showing help tags for views and controls using tooltip interactions

At a glance

Item Summary
Purpose Attach static, dynamic, and region-specific tooltips to UIKit views and controls.
App architecture ViewController composes tooltip-enabled views; UIToolTipInteraction delegates either remain on the controller or move into custom view subclasses that calculate their own configuration.
Main patterns Interaction-object composition, Delegate-configured behavior, Self-contained custom views
Project style Six Swift files; one storyboard controller plus small custom view/delegate types.

Project structure

Source bundle/
├── TooltipSample/
│   ├── AppDelegate.swift
│   ├── SceneDelegate.swift
│   ├── ViewController.swift
│   ├── TextViewWithTooltip.swift
│   ├── ViewWithBackgroundColorTooltip.swift
│   ├── ViewWithTooltipRegion.swift
│   ├── Base.lproj/
│   │   ├── LaunchScreen.storyboard
│   │   └── Main.storyboard
│   └── Info.plist
├── Configuration/
│   └── SampleCode.xcconfig
└── TooltipSample.xcodeproj/
    ├── .xcodesamplecode.plist
    └── project.pbxproj

Structure observations

  • The feature is composed in ViewController, not in the app delegate.
  • Default tooltips need only an interaction or toolTip value; dynamic and region-aware tooltips use delegate callbacks.
  • Custom view files colocate geometry/color knowledge with the delegate that uses it.

Overall architecture

Reference code

TooltipSample/ViewController.swift:99 — tooltip composition

    override func viewDidLoad() {
        super.viewDidLoad()
        containerStackView.addArrangedSubview(viewWithDefaultTooltip)
        containerStackView.addArrangedSubview(labelWithTooltip)
        containerStackView.addArrangedSubview(buttonWithTooltip)
        containerStackView.addArrangedSubview(viewWithBackgroundColorTooltip)
        containerStackView.addArrangedSubview(shoppingCartButtonWithTooltip)
        containerStackView.addArrangedSubview(viewWithTooltipRegion)
    }

Interpretation

The controller is a composition showcase. Each tooltip style is implemented at the narrowest useful boundary: static strings on views/interactions, controller state for the cart count, and view-local delegate logic when geometry or appearance belongs to a custom view.

Ownership and state

Ownership evidence

TooltipSample/ViewController.swift:74 — custom view and interaction construction

    lazy var viewWithBackgroundColorTooltip: UIView = {
        let view = ViewWithBackgroundColorTooltip()
        view.backgroundColor = UIColor.systemYellow
        let tooltipInteraction = UIToolTipInteraction()
        tooltipInteraction.delegate = view
        view.addInteraction(tooltipInteraction)
        return view
    }()
Owner Object or state Relationship Mutation authority
ViewController Lazy tooltip demonstration views Creates them and inserts them into its stack view The controller chooses the examples and mutates cartItemCount.
Each UIView Attached UIToolTipInteraction UIKit retains interactions added with addInteraction The view owns attachment lifetime; the assigned delegate supplies behavior.
ViewWithTooltipRegion Region geometry Computes from its own bounds The custom view alone decides which regions return a tooltip.
TextViewWithTooltip Text-range tooltip behavior Receives the interaction delegate role The text view maps hover positions to text-specific content.

Composition denotes source-visible construction and retained value state. Aggregation denotes a stored or injected collaborator whose exclusive lifetime the source does not prove.

Class and protocol design

TooltipSample/ViewWithTooltipRegion.swift:11 — region-specific tooltip delegate

class ViewWithTooltipRegion: UIView, UIToolTipInteractionDelegate {

    func toolTipInteraction(_ interaction: UIToolTipInteraction,
                            configurationAt point: CGPoint) -> UIToolTipConfiguration? {
        var topRect = self.bounds
        var bottomRect = self.bounds
        let partHeight = self.bounds.size.height / 3
        topRect.size.height = partHeight
    }
}
Type Responsibility Depends on or conforms to
ViewController Builds and presents the tooltip variants UIViewController, UIToolTipInteractionDelegate
TextViewWithTooltip Returns tooltip content for text positions UITextView, UIToolTipInteractionDelegate
ViewWithBackgroundColorTooltip Derives tooltip text from view appearance UIView, UIToolTipInteractionDelegate
ViewWithTooltipRegion Restricts tooltip activation to top/bottom regions UIView, UIToolTipInteractionDelegate

All capability protocols here are UIKit-defined. The separate conforming view types are useful delegation seams, but the sample does not define a local protocol abstraction.

Access control

Symbol Access Verified effect Design reason
Tooltip view/controller types implicit internal Visible throughout the app module Storyboard and sibling source files can construct them; external modules cannot.
Lazy demo views and cartItemCount implicit internal Other code in the module could access them The sample favors inspectable teaching code over a hardened library surface.
Tooltip delegate callbacks implicit internal Satisfy UIKit conformance inside the module They must be visible to the conformance witness, but need not be public.

Reference code

TooltipSample/ViewController.swift:10 — module-internal feature root

class ViewController: UIViewController {
    // ...
}

This sample has no meaningful public, open, or fileprivate feature boundary. Its unmodified declarations are internal, which fits a single application target; production code could make demo properties private if no tests or collaborators require them.

Logic ownership and placement

Logic Owning type or file Why it lives there
Example composition ViewController It owns the stack and demonstrates all supported tooltip styles.
Dynamic cart tooltip ViewController Tooltip text depends on controller-owned cartItemCount.
Region hit testing ViewWithTooltipRegion The view has the bounds needed to calculate hover regions.
Text/color-specific tooltip text TextViewWithTooltip and ViewWithBackgroundColorTooltip Behavior stays beside the UI state it interprets.

Design patterns

Pattern Source evidence Purpose or tradeoff
Interaction-object composition TooltipSample/ViewController.swift:21 and TooltipSample/ViewController.swift:68 Behavior is attached to existing views without subclassing every static case.
Delegate-configured behavior TooltipSample/ViewController.swift:116 Dynamic content is requested only when UIKit needs a tooltip.
Self-contained custom views TooltipSample/ViewWithTooltipRegion.swift:11 Geometry-dependent rules do not leak into the composition controller.

Naming conventions

  • Custom views state both subject and behavior (TextViewWithTooltip, ViewWithTooltipRegion).
  • Delegate callbacks keep UIKit’s toolTipInteraction(_:configurationAt:) vocabulary.
  • Lazy property names describe each demonstrated variant instead of generic view1/view2 labels.
  • Files follow their primary custom view type.

Architecture takeaways

  • Use an interaction object for attachable behavior and a delegate only when content is dynamic.
  • Put geometry- or appearance-dependent tooltip rules on the view that owns that knowledge.
  • Treat the controller as a demo composer; app lifecycle delegates are not part of the feature architecture.

Source map

Source file Architectural role
TooltipSample/ViewController.swift Example composition and dynamic cart tooltip
TooltipSample/TextViewWithTooltip.swift Text-aware tooltip delegate
TooltipSample/ViewWithBackgroundColorTooltip.swift Appearance-aware tooltip delegate
TooltipSample/ViewWithTooltipRegion.swift Region-aware tooltip delegate
TooltipSample/AppDelegate.swift / SceneDelegate.swift Application and scene lifecycle