From 28a91b638588e95a6a3bfbc9527b0f77ac2478ba Mon Sep 17 00:00:00 2001 From: osy <50960678+osy@users.noreply.github.com> Date: Wed, 16 Sep 2026 23:54:16 +0200 Subject: [PATCH] toolbar(iOS): keep hide toolbar tip off the toolbar on iOS 26+ From iOS 26 the arrow edge passed to popoverTip is only a preference. When the VM toolbar spans most of the screen width, the system attaches the "Tap to hide/show toolbar" tip beside the chevron instead of below it, covering the other toolbar buttons until the tip is dismissed. This happened on iPhone on iOS 26.1 and on iPhone and iPad on iOS 27. On iOS 26 and later, restrict the tip's arrow to the edge facing the toolbar, using the top edge when the toolbar is docked at the top and the bottom edge when it is docked at the bottom, so the tip always opens toward the middle of the screen. iOS 17 through 25 keep the existing behavior. Assisted-by: Claude:claude-opus-5 --- Platform/iOS/VMToolbarView.swift | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Platform/iOS/VMToolbarView.swift b/Platform/iOS/VMToolbarView.swift index c175b02a..2d0d58a7 100644 --- a/Platform/iOS/VMToolbarView.swift +++ b/Platform/iOS/VMToolbarView.swift @@ -166,7 +166,7 @@ struct VMToolbarView: View { Label("Hide", systemImage: isCollapsed ? nameOfHideIcon : nameOfShowIcon) }.toolbarButtonStyle(horizontalSizeClass: horizontalSizeClass, verticalSizeClass: verticalSizeClass) .animationUniqueID("hide", in: namespace) - .modifier(HideToolbarTipModifier(isCollapsed: $isCollapsed)) + .modifier(HideToolbarTipModifier(isCollapsed: $isCollapsed, location: location)) .opacity(toolbarToggleOpacity) .modifier(Shake(shake: shake)) .offset(dragOffset) @@ -477,15 +477,28 @@ extension MenuStyle where Self == ToolbarMenuStyle { private struct HideToolbarTipModifier: ViewModifier { @Binding var isCollapsed: Bool + let location: ToolbarLocation private let _hideToolbarTip: Any? + /// Keeps the tip on the side of the toolbar facing the middle of the screen. + /// + /// From iOS 26 a single arrow edge is only a preference, and when the toolbar spans most of + /// the width the system attaches the tip beside the button instead, covering the toolbar. + private var arrowEdges: Edge.Set { + switch location { + case .topLeft, .topRight: return .top + case .bottomLeft, .bottomRight: return .bottom + } + } + @available(iOS 17, *) private var hideToolbarTip: UTMTipHideToolbar { _hideToolbarTip as! UTMTipHideToolbar } - init(isCollapsed: Binding) { + init(isCollapsed: Binding, location: ToolbarLocation) { _isCollapsed = isCollapsed + self.location = location if #available(iOS 17, *) { _hideToolbarTip = UTMTipHideToolbar() } else { @@ -495,7 +508,13 @@ private struct HideToolbarTipModifier: ViewModifier { @ViewBuilder func body(content: Content) -> some View { - if #available(iOS 17, *) { + if #available(iOS 26, *) { + content + .popoverTip(hideToolbarTip, arrowEdges: arrowEdges) + .onAppear { + UTMTipHideToolbar.didHideToolbar = isCollapsed + } + } else if #available(iOS 17, *) { content .popoverTip(hideToolbarTip, arrowEdge: .top) .onAppear {