We use a UIScrollView but manage our own virtualization and when fast scrolling kicks in tvOS adds a secret child to our UIScrollView of type _UIFocusFastScrollingIndexBarView and gives it focus. I don't see shouldUpdateFocus being called for when this happens so I can't stop it. This is wreaking havok with our input and virtualization systems.
We've tried scrollView.indexDisplayMode = .alwaysHidden but that doesn't stop this.
Any way to disable tvOS's fast scrolling?
Correction, scrollView.indexDisplayMode = .alwaysHidden appears to stop the swipe on the right edge gesture but it does not stop the multiple-fast-swipes gesture. tvOS will still go into fast scroll mode and give focus to the widget that's hidden. I'll file a Radar.
This is one of the most annoying issues I have found with tvOS.
What I have found is that when a UIScrollView enters in this "fastFocus" scroll mode, the focus moves to UIView of type "UIFocusFastScrollingIndexBarView".
So what I did was put a check in my didUpdateFocus() function like so:
if let tempNextFocusView = context.nextFocusedView {
let desc = type(of: tempNextFocusView).description()
let isFastFocusMode = desc.contains("_UIFocusFastScrollingIndexBarView")
}
At least now I know when I am in this mode. One of the biggest issues I have is that it can be difficult to get a notification that the user has exited out of this mode. There are use-cases where none of my UIScrollView delegate functions are called - typically if the user does a bunch of fast swiping and then clicks to stop scrolling then scrolls again... No items will receive focus and none of the scrollView delegates are called. i.e., our QA can break this pretty easily.
I know this is old, but I've recently found a reliable way to prevent fast scroll mode. The key I found (with a little help from chat gpt), is to control the velocity of the scroll, adjusting it so that the system never thinks a fast scroll is happening. here's a bit of code I used to do this. The nice thing about this approach is that it doesn't limit any of the other scrolling behavior (long press scroll, etc)
if abs(velocity.y) > 0.75 { /// There is a threshold here that tells the system to go into "fast-scroll" mode
/// Reduce the target offset by a fraction to control fast scrolling
let newTargetY = scrollView.contentOffset.y + (targetContentOffset.pointee.y - scrollView.contentOffset.y) * 0.9
/// Only apply this if we are passed the first row, otherwise allow the natural deceleration
if newTargetY > collectionViewLayout.gridCellHeight {
targetContentOffset.pointee.y = newTargetY
}
}
}