Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions Sources/Bonsplit/Internal/Views/TabBarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -259,16 +259,16 @@ struct TabBarView: View {
controller.requestTabContextAction(action, for: TabID(id: tab.id), inPane: pane.id)
}
)
.background(
GeometryReader { geometry in
Color.clear.preference(
key: SelectedTabFramePreferenceKey.self,
value: pane.selectedTabId == tab.id
? geometry.frame(in: .named("tabBar"))
: nil
)
.background {
if pane.selectedTabId == tab.id {
GeometryReader { geometry in
Color.clear.preference(
key: SelectedTabFramePreferenceKey.self,
value: geometry.frame(in: .named("tabBar"))
)
}
}
)
}
Comment on lines +262 to +271
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential one-frame separator flicker on tab switch

With the old approach every tab always had a live GeometryReader in its background, so when selection moved from tab A to tab B the new GeometryReader (for B) was already laid out and could publish frame_B in the same render pass that tab A's GeometryReader went silent. With the new approach the GeometryReader for tab B is inserted for the first time on that render pass. SwiftUI needs to lay it out before it can publish a frame, which may introduce a single-frame window where no view publishes a preference value and SelectedTabFramePreferenceKey temporarily resolves to its defaultValue of nil. During that frame, tabBarBackground would render the separator as full-width (no gap) before the correct gap is restored on the next layout pass.

In practice this flicker (≤16 ms at 60 fps) is likely imperceptible during normal tab switching, but it is a subtle behavioral difference worth being aware of. If it ever becomes noticeable, one mitigation is to keep the previous frame cached in tabBarBackground until the preference produces a non-nil value:

.onPreferenceChange(SelectedTabFramePreferenceKey.self) { frame in
    if let frame {
        selectedTabFrameInBar = frame
    }
    // Intentionally skip nil to avoid a one-frame gap during tab transitions.
}

This keeps selectedTabFrameInBar at the last-known good frame during the brief transition window.

.onDrag {
createItemProvider(for: tab)
} preview: {
Expand Down
Loading