Jaggy, Laggy, low-fps scrolling on iPhone 13 Pro (Pro Motion Display) for .offset

I created a horizontally scrolling view modifier that essentially wraps the contents and applies a horizontal offset based on a DragGesture GestureState.

It looks a little bit like this

@GestureState private var dragOffset: CGFloat = 0
content  
.offset(x: dragOffset, y: 0)
  .simultaneousGesture(DragGesture(minimumDistance: 20, coordinateSpace: .global)
  .updating($dragOffset) { (value, gestureState, transaction) in
                            gestureState = value.translation.width
                        })

The problem I am seeing is that on the Pro Motion Display of the iPhone 13 Pro, the "offset" view does not smoothly slide along with your finger as it drags. Instead is is very jaggy or laggy, probably rendered with maybe 15 fps or so. On the iPhone 11 Pro I used before, the drag is very smooth and on the iOS 15 simulator it is smooth as well.

What is wrong here? Thanks for help!

I posted this as FB9657760

I have the same stutter scrolling on a pro-motion device when using a regular UIScrollview and a content offset. Older devices work fine, turning off pro-motion on the iphone 13 stops it too.

If anyone comes here for a solution. I still believe this is a bug in DragGesture but there is workaround possible though CADisplayLink. (See here: https://developer.apple.com/documentation/quartzcore/optimizing_promotion_refresh_rates_for_iphone_13_pro_and_ipad_pro)

Unfortunately, you will have to create a helper object to setup a display link, because you can't have @objc functions in structs. I created:

@available(iOS 15.0, *)
class RefreshRateHelper {

    static let shared = RefreshRateHelper()
    
    private var displayLink:CADisplayLink? = nil

   init() {
        displayLink = CADisplayLink(target: self, selector: #selector(ignore))
        displayLink?.add(to: .current, forMode: .default)
    }

    @objc
    func ignore(link: CADisplayLink) {
    }

    func preferredFrameRateRange(_ range:CAFrameRateRange){
        displayLink?.preferredFrameRateRange = range
    }        

}

This very hacky. It basically is a globally accessible display link that you give a preferred framerate. I ended up setting a high framerate in .updating and resetting it to .default in onEnded.

I hope this helps someone.

I don’t think it’s related to pro display. There’s a lag and lower frame rate with DragGesture compared to PanGesture. Filled FB9781201

I'm seeing a similar issue.

FWIW I'm experiencing this just using the offset() in SwiftUI, no scroll views or gestures involved. On the iPhone 13 pro the updates run horribly (fps seems to degrade over time?), yet iPhone X and other non 120hz phones are updating at rock solid 60fps.

Same on iOS 17.

Jaggy, Laggy, low-fps scrolling on iPhone 13 Pro (Pro Motion Display) for .offset
 
 
Q