Skip to content

Toggle position is incorrect in OpenSwiftUI View Renderer #876

@Kyle-Ye

Description

@Kyle-Ye

Summary

Toggle can render its backing platform switch outside the visible content area when using the OpenSwiftUI View Renderer.

The same view renders correctly with SwiftUI, but under OSUI the UISwitch exists in the UIKit hierarchy while it is not visible in the expected location.

Reproduction

Use a minimal Toggle label that contains a large content view:

struct ToggleExample: View {
    @State private var toggle = true

    var body: some View {
        Toggle(isOn: $toggle) {
            Color.red
        }
    }
}

Run the example with the OpenSwiftUI View Renderer enabled.

Expected Behavior

The switch should be visible and positioned the same way as the SwiftUI-backed rendering path.

Actual Behavior

The red content renders, but the switch is not visible in the expected position. Inspecting the UIKit hierarchy shows the platform switch exists, but it is placed under an inherited wrapper and offset outside the visible content area.

The observed hierarchy shape differs from SwiftUI:

  • SwiftUI places PlatformViewHost<Switch> directly under the hosting view.
  • OSUI places PlatformViewHost<Switch> under _UIInheritedView, and the platform view position is effectively applied relative to that wrapper.

This causes the switch to be present but visually misplaced.

Notes

A compatibility fix is proposed in #875.

Log

OpenSwiftUI ViewRenderer

(lldb) po [0x105f16830 recursiveDescription]
<_TtGC11OpenSwiftUI14_UIHostingViewGV15OpenSwiftUICore15ModifiedContentVS1_7AnyViewVS_12RootModifier__: 0x105f16830; frame = (0 0; 402 874); autoresize = W+H; backgroundColor = <UIDynamicSystemColor: 0x60000173ab40; name = systemBackgroundColor>; layer = <OpenSwiftUI.UIHostingViewDebugLayer: 0x600000248d60>>
   | <OpenSwiftUI._UIGraphicsView: 0x10881d5d0; frame = (0 62; 345 778); anchorPoint = (0, 0); autoresizesSubviews = NO; backgroundColor = UIExtendedSRGBColorSpace 1 0.231373 0.188235 1; layer = <CALayer: 0x600000250680>>
   | <OpenSwiftUI._UIInheritedView: 0x10881dd10; frame = (353 435.667; 49 31); anchorPoint = (0, 0); autoresizesSubviews = NO; layer = <CALayer: 0x600000250880>>
   |    | <_TtGC11OpenSwiftUI16PlatformViewHostGVS_P10$109c4754c32PlatformViewRepresentableAdaptorVS_P10$109c4c72c6Switch__: 0x10881b660; baseClass = _UIConstraintBasedLayoutHostingView; frame = (353 435.667; 49 31); anchorPoint = (0, 0); layer = <CALayer: 0x600000250180>>
   |    |    | <UISwitch: 0x105d08380; frame = (0 0; 51 31); autoresize = W+H; gestureRecognizers = <NSArray: 0x600000010860>; layer = <CALayer: 0x60000024f180>>
   |    |    |    | <UISwitchModernVisualElement: 0x105d11c00; frame = (0 0; 51 31); gestureRecognizers = <NSArray: 0x6000002050c0>; layer = <CALayer: 0x60000024f200>>
   |    |    |    |    | <UIView: 0x1088168a0; frame = (0 0; 51 31); backgroundColor = <UIDynamicSystemColor: 0x600001717040; name = _switchOffColor>; layer = <CALayer: 0x600000247e20>>
   |    |    |    |    | <UIView: 0x108816720; frame = (0 0; 51 31); layer = <CALayer: 0x600000247de0>>
   |    |    |    |    |    | <UIImageView: 0x1088114c0; frame = (-459 0; 510 31); hidden = YES; opaque = NO; userInteractionEnabled = NO; image = <UIImage:0x60000300d320 CGImage anonymous; (510 1)@3>; layer = <CALayer: 0x600000244c20>>
   |    |    |    |    |    | <UIView: 0x10881b020; frame = (0 0; 51 31); layer = <CALayer: 0x600000250020>>
   |    |    |    |    |    |    | <UIImageView: 0x10881ac60; frame = (38.6667 16; 0 0); userInteractionEnabled = NO; tintColor = <UIDynamicSystemColor: 0x600001715e40; name = _switchOffImageColor>; image = <(null):0x0 (null) anonymous; (0 0)@0>; layer = <CALayer: 0x600000242220>>
   |    |    |    |    |    |    | <UIImageView: 0x10881ae40; frame = (12 16; 0 0); alpha = 0; userInteractionEnabled = NO; tintColor = UIExtendedGrayColorSpace 1 1; image = <(null):0x0 (null) anonymous; (0 0)@0>; layer = <CALayer: 0x600000247f80>>
   |    |    |    |    |    | <UIImageView: 0x108816d90; frame = (-6 -3; 43 43); opaque = NO; userInteractionEnabled = NO; image = <_UIResizableImage:0x600003b12760 CGImage anonymous; (43 43)@3>; layer = <CALayer: 0x600000219880>>

SwiftUI View Renderer

(lldb) po [0x104215990 recursiveDescription]
<_TtGC11OpenSwiftUI14_UIHostingViewGV15OpenSwiftUICore15ModifiedContentVS1_7AnyViewVS_12RootModifier__: 0x104215990; frame = (0 0; 402 874); autoresize = W+H; backgroundColor = <UIDynamicSystemColor: 0x600001720640; name = systemBackgroundColor>; layer = <OpenSwiftUI.UIHostingViewDebugLayer: 0x6000002373e0>>
   | <OpenSwiftUI._UIGraphicsView: 0x10431b9c0; frame = (0 62; 345 778); anchorPoint = (0, 0); autoresizesSubviews = NO; backgroundColor = UIExtendedSRGBColorSpace 1 0.231373 0.188235 1; layer = <CALayer: 0x60000023ae80>>
   | <_TtGC11OpenSwiftUI16PlatformViewHostGVS_P10$107ef80d832PlatformViewRepresentableAdaptorVS_P10$107efd2ac6Switch__: 0x10430e780; baseClass = _UIConstraintBasedLayoutHostingView; frame = (353 435.667; 49 31); anchorPoint = (0, 0); layer = <CALayer: 0x60000023ab00>>
   |    | <UISwitch: 0x10440bd50; frame = (0 0; 51 31); autoresize = W+H; gestureRecognizers = <NSArray: 0x60000000d0b0>; layer = <CALayer: 0x600000233ae0>>
   |    |    | <UISwitchModernVisualElement: 0x10440e170; frame = (0 0; 51 31); gestureRecognizers = <NSArray: 0x60000023a560>; layer = <CALayer: 0x600000233b60>>
   |    |    |    | <UIView: 0x104416cf0; frame = (0 0; 51 31); backgroundColor = <UIDynamicSystemColor: 0x600001728900; name = _switchOffColor>; layer = <CALayer: 0x60000023cbe0>>
   |    |    |    | <UIView: 0x104416b70; frame = (0 0; 51 31); backgroundColor = <UIDynamicCatalogSystemColor: 0x60000170ff40; name = systemGreenColor>; layer = <CALayer: 0x60000023cba0>>
   |    |    |    |    | <UIImageView: 0x104411bd0; frame = (0 0; 510 31); hidden = YES; opaque = NO; userInteractionEnabled = NO; image = <UIImage:0x6000030093b0 CGImage anonymous; (510 1)@3>; layer = <CALayer: 0x60000023c640>>
   |    |    |    |    | <UIView: 0x1043178f0; frame = (0 0; 51 31); layer = <CALayer: 0x60000023a9a0>>
   |    |    |    |    |    | <UIImageView: 0x10430fe50; frame = (38.6667 16; 0 0); alpha = 0; userInteractionEnabled = NO; tintColor = <UIDynamicSystemColor: 0x600001720f00; name = _switchOffImageColor>; image = <(null):0x0 (null) anonymous; (0 0)@0>; layer = <CALayer: 0x60000023a840>>
   |    |    |    |    |    | <UIImageView: 0x104310030; frame = (12 16; 0 0); userInteractionEnabled = NO; tintColor = UIExtendedGrayColorSpace 1 1; image = <(null):0x0 (null) anonymous; (0 0)@0>; layer = <CALayer: 0x60000023a900>>
   |    |    |    |    | <UIImageView: 0x104309740; frame = (14 -3; 43 43); opaque = NO; userInteractionEnabled = NO; image = <_UIResizableImage:0x600003b1c1c0 CGImage anonymous; (43 43)@3>; layer = <CALayer: 0x6000002385c0>>

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: compatibilityCompatibility, availability, legacy support, and cross-version behavior.area: hosting-bridgeSwiftUI bridge, UIHosting/NSHosting, representables, and platform host views.area: renderingDisplayList, render backends, renderer hosts, drawing, and effects.impact: visual-diffVisual mismatch, screenshot diff, or rendering fidelity issue.type: bugSomething is not working correctly.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions