Repository navigation
Implement fadingEdgeLength for ScrollView on iOS - #59003
Open
YevheniiKotyrlo wants to merge 2 commits into
Open
YevheniiKotyrlo wants to merge 2 commits into
YevheniiKotyrlo wants to merge 2 commits into
Conversation
ScrollView declares fadingEdgeLength on its cross-platform props, but only
Android implements it. The iOS view config does not list it and the cxx
HostPlatformScrollViewProps has no field for it, so iOS drops the value.
RCTScrollViewComponentView masks the inner UIScrollView's layer with a
CAGradientLayer in which each edge fades over its own length at full
strength, which is what Android draws for {start, end}. The iOS view config
forwards fadingEdgeLength and horizontal, so the mask follows the declared
axis, and the prop moves to the shared props in Flow, the TypeScript types
and the API snapshot.
Contributor
Author
YevheniiKotyrlo
marked this pull request as ready for review
October 12, 2026 04:52
|
Warning JavaScript API change detected This PR commits an update to
This change was flagged as: |
fadingEdgeLength is a shared ScrollView prop in Flow and TypeScript, but the C++ props declared it twice: on Android's HostPlatformScrollViewProps and on a cxx HostPlatformScrollViewProps written only to carry it. It now lives in BaseScrollViewProps, where both platforms parse it, and the cxx props are an alias of the base again. Android's diff keeps reporting it among the base props. horizontal now resets to false when the prop is removed, as its declared default is. It reset to true, which only iOS reads, so a ScrollView whose horizontal prop was removed faded along its width.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary:
ScrollViewdeclaresfadingEdgeLengthon its cross-platform props, but only Android implements it. On iOS the value never reaches native code — the iOS view config does not list it and the cxxHostPlatformScrollViewPropshas no field for it — so a scroller whose overflow cue is its fading edge shows none, usually with its scroll indicator turned off beside it.This implements it on iOS.
RCTScrollViewComponentViewmasks the innerUIScrollView's layer with aCAGradientLayerin which each edge fades over its own length at full strength, which is what Android draws for{start, end}(AOSP scales the fade byfadeHeight × strength, and the strength isvalue / max(start, end)); a number fades both edges. The mask is re-framed to the scroll view's bounds on scroll so it stays fixed to the viewport, mirrors with the scroll view in RTL sostartandendstay logical, and is removed for a zero pair. It sits on the scroll view rather than the component view becauseRCTViewComponentViewowns the component view'slayer.maskfor clipping rounded corners.The iOS view config now forwards
fadingEdgeLengthandhorizontal— the mask follows the declared axis, as Android does, rather than thecontentSizeheuristic, which would orient it wrongly while the content fits — and the prop moves to the shared props: fromScrollViewPropsAndroidin Flow, the TypeScript types and the API snapshot, and from Android'sHostPlatformScrollViewPropstoBaseScrollViewPropsin C++, where both platforms parse it.horizontalnow resets tofalsewhen the prop is removed, as its declared default is; it reset totrue, and the mask is the only code that reads it. The RNTester example is shared now and shows0,40and{start: 0, end: 80}side by side, each on a horizontal and a vertical scroller.Changelog:
[IOS] [ADDED] -
ScrollViewand the lists built on it supportfadingEdgeLengthon iOSTest Plan:
RCTScrollViewComponentViewTests, eight new cases: each edge's own length, a number on both edges, a horizontal scroll view, lengths that would overlap, zero removing the mask, the mask following the content offset, a resized scroll view, and props parsed from a raw update that removeshorizontal.React-RCTFabric'sTestsspec passes on an iOS 18.0 simulator, 62 tests with 0 failures. No Podfile enables that spec, andRCTParagraphComponentViewTests.mmdoes not compile under CocoaPods because no pod packagesreact/renderer/element, so I ran it with:testspecs => ['Tests']and that file excluded. Never building the mask fails the seven mask cases; never re-framing it on scroll fails the content-offset case; withhorizontalresetting totrue, the parsed case's mask stays along the width.fadingEdgeLengthon an iPhone 16 simulator, iOS 18.0, before and after: the pair. The0row is pixel-identical, and the{start: 0, end: 80}row changes only at its end edges.flow full-check, ESLint and Prettier on the changed files,node scripts/clang-format.js --check,yarn test-typescript-legacy,yarn build-types(snapshot regenerated),yarn test-generated-typescriptandyarn cxx-api-validate(Doxygen 1.16.1, Linux; the three Frameworks snapshots regenerated) pass.