May 11, 2015
  • All
  • Ionic

Native Scrolling in Ionic: A Tale in Rhyme

Perry Govier


intro-once upon a time, the Web Wizard was befuddled. “How can I add scroll-based features without scrolling events?” he muddled. Try as he might, he couldn’t get fake events right, so he called his advisors together for a huddle.

“Scrolling’s complicated,” he stated. “The reasons to avoid JS scrolling have faded.” So JS scrolling was enabled, and the features it allowed were fabled. It appeared JS scrolling was underrated.

Javascript scrolling had saved the day, and it lifted Ionic above the fray. But as the project quickly grew, its developers truly knew the reasons for JS scrolling would fall away.

As iOS and Android matured, native scrolling events were assured. “The time has come,” the Web Wizard said, “for native scrolling now to spread. A new functionality must be procured.”

Pull to Refresh; List Reordering; Infinite Scroll: All were configured to meet this goal. Even the $ionicScrollDelegate was carefully made to relegate itself to optional native scroll view control.

Once these changes were complete, there appeared a problem with collection-repeat. After conducting an investigation, the necessary changes caused frustration; they totaled JS scrolling nearly complete.

The solution that was committed was for JS scrolling to be permitted. Collection repeat would trigger Javascript scrolling to rigor, and native scrolling would be acquitted.

It is now my privilege to announce native scrolling’s time to pounce. For the devices that support it, you no longer must port it. Yes, it even has that native bounce!

The Real Story

Ionic was created in the fall of 2013, which by all accounts is just year and a half ago. But in mobile web time, it was a generation ago! Back then, iOS 6 still had dominant market share, and Android 2.3 demanded support.

Among other things, those browsers lacked proper scroll events. This meant that to pull off features like pull to refresh and infinite scrolling, JS scrolling would be required. Once we added it, we found we were also able to do things like list reordering and even collection-repeat.

Javascript scrolling has worked very well for Ionic, enabling us to do things that were simply impossible without it. It does use up a significant amount of processor time, though, and it requires that a lot of native functionality around touch events and input element behavior be reworked. In some ways, it’s been both a blessing and a curse.

However, Android 4.1+ supports native scroll events, and now with Lollipop and chromium webviews, those scroll events are asynchronous and won’t interrupt the smooth display of scrolling behavior. It’s an exciting time for scroll events in Android!

On the other hand, iOS is a bit of a different story. With iOS 8, Apple introduced WkWebView, which includes native scroll events. The one problem, though, is in iOS 8 Beta 3, WkWebView’s support for the file protocol broke and was never fixed. That meant that Cordova was stuck using the UIWebView that had been mostly unchanged since iOS 7, which lacked complete native scroll events.

One popular solution is to bind to touchmove events and create fake scroll events. This works nicely, until the user lets go, and iOS’s inertia scrolling takes over. We were able to accurately recreate Apple’s inertia formula but unable to get a consistently accurate read of the velocity that that equation depends on, because that’s determined in native land. We’re only provided occasional touchmove events to guess. Turns out 18ms is a long time when it comes to determining accurate velocity, and our best tests still had a 30% margin of error.

This means that iOS, for the time being, still requires JS scrolling. Android, however, gets to enjoy Ionic’s new native scrolling support. Pull to Refresh, Infinite Scrolling, List Reordering, and the $ionicScrollDelegate all work with native scrolling now!

One important caveat is that because of how collection-repeat works, it requires rapidly shifting the scroll content, hijacking the scroll behavior, and recreating the scrollbar. That’s pretty much JS scrolling, so we set it so that collection-repeat will force an ion-content to use JS scrolling.

Native scrolling can be enabled using overflow-scroll=”true” on your ion-content or using the $ionicConfigProvider to set it globally in current versions of Ionic. We want to let it be a bit more battle tested before making it the default in Android, but give it a shot in the current nightly and let us know how it’s working for you!

Perry Govier