Post

Replies

Boosts

Views

Activity

Reply to ScrollView still doesn’t support scrolling to a specific item when the user stops dragging?
I tried but failed to get a lab appointment for this issue, having submitted Feedback for it "ScrollView cannot be used to "snap" child views to a specific on-screen region" (FB7784831). Here's the content of the FB and the sample code: We need to be able to replicate the UIKit-era behaviours of UIScrollViewDelegate where we could handle scrollViewWillEndDragging and receive the anticipated scroll end point and amend it if necessary, to make items “snap” to align to a certain location on screen, rather than just permitting free scrolling. This seems like it is still not possible in SwiftUI, if you e.g. envision creating something like the old iOS date picker which “snaps” the item nearest to a guide (e.g. center) when the user ceases scrolling. We have tried various techniques, with the worst and most painful being using a totally custom View and custom offsetting of the content when a drag gesture onChange occurs, and projecting out the final offset when onEnded occurs. This does not feel correct on any platform as the animation inertia curves aren’t perfect and obviously has performance issues for large lists. It feels like ScrollViewReader gets us very close to being able to do this so I would love your input on how to achieve this very old capability we’ve had in UIKit since iOS 5! Attached is a sample project that shows an attempt to get close to this using the new ScrollViewReader. The sample: does not attempt to capture geometry of each scroll view child, for simplicity attempts to capture a “did end dragging” equivalent by using a simultaneous drag gesture on each child view, but onEnded does not get called in current iOS 14 betas does not attempt to scroll to the correct location because the event never triggers, and the sample does capture the geometry yet - and the scrollTo function on ScrollViewProxy does not seem to offer the required ability to either simply scroll to a specific Y offset (based on the Y offset of the child nearest to the predicted end location of the drag) or the ability to scroll item with a given ID to align a specific edge e.g. ID’s .top with a specific scroll offset in the scroll view. e.g. “align item “N” top to y = 500”. If the above can be made to work that would be great. However it seems a vastly preferable, if old fashioned solution, would be to have an: .onScrollingWillEnd { offset -> CGPoint in … } …event modifier on ScrollView so that we could receive the anticipated scroll offset and return a modified version if we want to. Even better would be something like: ScrollView { 		… child views … } .onScrollingWillEnd { offset -> ScrollTarget in 	 return ScrollTarget(id: findIDOfChildNearest(to: offset), 				anchor: .top, // Align the top of the view with the given ID 				toAnchor: mySnapPointAnchor) // to this anchor point which might be in another coordinate space }
Jun ’20
Reply to ScrollView still doesn’t support scrolling to a specific item when the user stops dragging?
It's worth noting that in the gist the simultaneous drag gesture triggers onChanged but not onEnded. This might be a bug, but maybe the simultaneous drag alongside the ScrollView drag is never considered truly "Recognised" so it does not end? There's a possible workaround to use onChanged to set some state (the translation), monitor that state for changes using the new onChange and applying some hysteresis to this using a publisher, such that when there is no new change for ~ 50ms, we can then alter some state to trigger a call to the ScrollViewReader.scrollTo?
Jun ’20
Reply to ScrollView still doesn’t support scrolling to a specific item when the user stops dragging?
I have tried a workaround suggested elsewhere whereby: We use the onChange of the simultaneous drag gesture applied to each child view of the ScrollView to pass the child ID and offset to a publisher that is debounced at e.g. 50ms We onReceive the debounced publisher and use the value to call scrollProxy.scrollTo(id:,anchor:) This mechanism works to "detect" the end of a scroll interaction by the user, but the scrollTo seems to be too "smart" in that we cannot control the exact scroll offset to move to. This makes it impossible to lock to a specific position on screen. It seems the anchor argument to scrollTo is merely a "point relative to the sub view identified by ID which should definitely be on screen" rather than an actual location where the view with that ID should be. I think therefore scrollTo is not currently usable for this purpose of specific a specific content offset in the ScrollView. If that is true this is all for nought and while we can hack detecting the end of scrolling like this, we still can't direct the ScrollView to a specific offset. Any chance we can get a little API improvement on this during betas?
Jun ’20
Reply to ScrollView still doesn’t support scrolling to a specific item when the user stops dragging?
I've updated the example to fix some bugs, new code is at: https://gist.github.com/marcpalmer/c48a56e26b2319e5b43c2ad6973ad4d4 This example now shows that scrollTo works but only scrolls to e.g. the center of the scroll view (a unit point within it) and cannot seemingly be used to scroll item with ID to a specific Y offset such that e.g. the view with the ID's top is aligned with the desired Y. You could fake this by calculating what unit point in the ScrollView coordinate system will yield the "snap" point you want, but this will not align the view correctly to that as the anchor unitpoint is apparently shared between the ScrollView and the view you are scrolling, which seems like strange behaviour. I would suggest an API change there so that the two anchors can be specified independently. Secondly, the sample shows that onChanged is emitted for a simultaneous drag gesture but not onEnded. We need onEnded for this mechanism of detecting the end of scrolling to work as monitoring onChange for when it "stops changing" is fraught with problems.
Jun ’20
Reply to is Anyone experiencing freezing when attempting to get CVPixelBuffer from AVAssetReaderOutput in iOS16?
Hi hyunjin, I am seeing this too, sometimes when I try to cancel my video export the SwiftUI AsyncRenderer deadlocks in a similar way, albeit not on the main thread: * thread #17, name = 'com.apple.SwiftUI.AsyncRenderer'   * frame #0: 0x00000002018c6b48 libsystem_kernel.dylib`__psynch_mutexwait + 8     frame #1: 0x0000000211d29150 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84     frame #2: 0x0000000211d30310 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248     frame #3: 0x00000001c638056c QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double, double*) + 388     frame #4: 0x00000001c63b55ec QuartzCore`CA::Transaction::commit() + 652     frame #5: 0x00000001c639e8cc QuartzCore`CA::Transaction::flush_as_runloop_observer(bool) + 88     frame #6: 0x00000001c4d55d60 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36     frame #7: 0x00000001c4cde2d0 CoreFoundation`__CFRunLoopDoObservers + 532     frame #8: 0x00000001c4d44f30 CoreFoundation`CFRunLoopRunSpecific + 704     frame #9: 0x00000001bf0e2334 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 212     frame #10: 0x00000001bf0e21c8 Foundation`-[NSRunLoop(NSRunLoop) run] + 64     frame #11: 0x00000001c8709030 SwiftUI`___lldb_unnamed_symbol64823 + 800     frame #12: 0x00000001c8707168 SwiftUI`___lldb_unnamed_symbol64774 + 88     frame #13: 0x00000001bf0fb808 Foundation`__NSThread__start__ + 716     frame #14: 0x0000000211d286cc libsystem_pthread.dylib`_pthread_start + 148 I have not been able to establish the cause or a workaround.
Nov ’22