When showing a popover:
struct ValueRowView<Content: View, PopoverContent: View> : View
{
let label: String
let value: Content
@State private var showPopover: Bool = false
let popoverContent: PopoverContent?
init(label: String, value: Content, @ViewBuilder popoverContent: () -> PopoverContent? = { nil })
{
self.label = label
self.value = value
self.popoverContent = popoverContent()
}
var body: some View
{
HStack
{
VStack(alignment: .leading)
{
Text(label)
.font(.footnote)
.foregroundColor(.gray)
value
}
Spacer()
if let popoverContent
{
Button(action:
{
showPopover.toggle()
})
{
Image(systemName: "info.circle")
.foregroundColor(.accentColor)
}
.popover(isPresented: $showPopover, attachmentAnchor: .point(.center))
{
ScrollView //TODO: Shows scroll indicator in popover arrow; iOS 26 bug?
{
popoverContent
.fixedSize(horizontal: false, vertical: true)
.padding()
.presentationCompactAdaptation(.popover)
}
.frame(width: UIDevice.current.userInterfaceIdiom == .phone ? 270 : 400)
}
}
}
}
}
extension ValueRowView where PopoverContent == EmptyView
{
init(label: String, value: Content)
{
self.label = label
self.value = value
self.popoverContent = nil
}
}
The scroll indicator isn't visible next to the scrolled content. Instead it runs outside the popover and shows up on the popover arrow/triangle (see image).
How to prevent this?
I would agree that this looks like a small bug.
I think what may be happening is that the scroll indicator is being shown in the trailing safe area inset. In your example, the pointer arrow is on the right side and it seems that this is also using the safe area inset. With the arrow on the right, the rest of the area for the trailing inset is masked out. So the only part of the scroll indicator that you see is the part that runs through the arrow.
Here are two possible workarounds:
ScrollView
, to break contact with the safe area inset:.popover(isPresented: $showPopover, attachmentAnchor: .point(.center)) {
ScrollView {
popoverContent
.fixedSize(horizontal: false, vertical: true)
.padding()
.presentationCompactAdaptation(.popover)
}
.padding(.trailing, 1) // 👈 here
.frame(width: UIDevice.current.userInterfaceIdiom == .phone ? 270 : 400)
}
.contentMargins
for .scrollIndicators
to the ScrollView
:.popover(isPresented: $showPopover, attachmentAnchor: .point(.center)) {
ScrollView {
popoverContent
.fixedSize(horizontal: false, vertical: true)
.padding()
.presentationCompactAdaptation(.popover)
}
.contentMargins(16, for: .scrollIndicators) // 👈 here
.frame(width: UIDevice.current.userInterfaceIdiom == .phone ? 270 : 400)
}
Both workarounds work similarly:
Of course, another workaround is to move the info button to the leading side of the content. This causes the pointer arrow to switch sides, so the trailing inset is not masked out and the scroll indicator remains visible.