Hey all,
Ran into a fun one on macOS 26.4.1 / Xcode 26.4.1, and I think I've narrowed it down enough to be worth sharing.
Symptom: HSplitView's divider drags fine, but the cursor never changes to the resize cursor on hover. Just stays as the regular arrow.
The cause (in my case):
the HSplitView was conditionally rendered via an outer if let:
struct PlayerDetailsView: View {
let theme: Theme
var playerVM = PlayerViewModel.shared
var body: some View {
let grayscaleCM = ColorMap(table: .grayscale)
ZStack {
VStack(spacing: 0) {
Rectangle()
.fill(LinearGradient(colors: [Color.black.opacity(0.45), Color.black.opacity(0)], startPoint: .top, endPoint: .bottom))
.frame(height: 8)
Spacer()
Rectangle()
.fill(LinearGradient(colors: [Color.black.opacity(0.45), Color.black.opacity(0)], startPoint: .bottom, endPoint: .top))
.frame(height: 8)
}
.allowsHitTesting(false)
if let disc = playerVM.disc {
HSplitView {
DiscInfoView(
disc: disc,
theme: theme,
)
.frame(minWidth: 720, alignment: .topLeading)
.buttonShadow()
.focusable(false)
TrackListView(
theme: theme,
playbackSequence: playerVM.tracksInPlaybackSequence,
bonusTrackStartIndex: playerVM.player.disc?.releaseMetadata?.firstBonusTrackIndex,
bonusTracksTitle: playerVM.player.disc?.releaseMetadata?.bonusTracksTitle,
bonusTracksDisabled: playerVM.bonusTracksDisabled,
onBonusIconTap: {
playerVM.player.bonusTracksDisabled.toggle()
}
)
.frame(minWidth: 512)
.focusable(false)
}
}
}
.background(
LinearGradient(
colors: [
grayscaleCM.color(for: 0.23),
grayscaleCM.color(for: 0.17),
],
startPoint: .top,
endPoint: .bottom
)
)
}
}
The fix:
move the conditional inside the HSplitView, so the split view itself is always present in the hierarchy (swap line 21 and 22 of code above):
HSplitView {
if let disc = playerVM.disc {
DiscInfoView(
disc: disc,
theme: theme,
)
.frame(minWidth: 720, alignment: .topLeading)
.buttonShadow()
.focusable(false)
TrackListView(
theme: theme,
playbackSequence: playerVM.tracksInPlaybackSequence,
bonusTrackStartIndex: playerVM.player.disc?.releaseMetadata?.firstBonusTrackIndex,
bonusTracksTitle: playerVM.player.disc?.releaseMetadata?.bonusTracksTitle,
bonusTracksDisabled: playerVM.bonusTracksDisabled,
onBonusIconTap: {
playerVM.player.bonusTracksDisabled.toggle()
}
)
.frame(minWidth: 512)
.focusable(false)
}
}
I asked Claude AI about it and its guess is that conditionally inserting the HSplitView causes its underlying NSSplitView to get torn down and rebuilt on view updates, and the tracking areas responsible for the resize cursor never get a chance to settle.
But that would be great to have a confirmation from someone at Apple who knows what's happening under the hood.
Is this a known issue or an Expected behavior?
Filed as FB22712819 in case anyone wants to duplicate.
I posted this in case anyone had the same very specific issue...
Cheers!