77 * of patent rights can be found in the PATENTS file in the same directory.
88 *
99 * @providesModule ScrollView
10- * @flow
1110 */
1211'use strict' ;
1312
@@ -25,6 +24,7 @@ const {
2524 requireNativeComponent,
2625} = ReactNative ;
2726
27+ const createReactClass = require ( 'create-react-class' ) ;
2828const PropTypes = require ( 'prop-types' ) ;
2929const ColorPropType = require ( 'react-native/Libraries/StyleSheet/ColorPropType' ) ;
3030const ScrollResponder = require ( 'react-native/Libraries/Components/ScrollResponder' ) ;
@@ -36,6 +36,9 @@ const ViewStylePropTypes = require('react-native/Libraries/Components/View/ViewS
3636const dismissKeyboard = require ( 'react-native/Libraries/Utilities/dismissKeyboard' ) ;
3737const invariant = require ( 'fbjs/lib/invariant' ) ;
3838const processDecelerationRate = require ( 'react-native/Libraries/Components/ScrollView/processDecelerationRate' ) ;
39+ const warning = require ( 'fbjs/lib/warning' ) ;
40+
41+ import type { NativeMethodsMixinType } from 'ReactNativeTypes' ;
3942
4043/**
4144 * Forked from https://github.com/facebook/react-native/blob/0.45-stable/Libraries/Components/ScrollView/ScrollView.js
@@ -75,7 +78,8 @@ const processDecelerationRate = require('react-native/Libraries/Components/Scrol
7578 * supports out of the box.
7679 */
7780// $FlowFixMe(>=0.41.0)
78- const ScrollView = React . createClass ( {
81+ const ScrollView = createReactClass ( {
82+ displayName : 'ScrollView' ,
7983 propTypes : {
8084 ...ViewPropTypes ,
8185 /**
@@ -138,16 +142,18 @@ const ScrollView = React.createClass({
138142 * These styles will be applied to the scroll view content container which
139143 * wraps all of the child views. Example:
140144 *
141- * return (
142- * <ScrollView contentContainerStyle={styles.contentContainer}>
143- * </ScrollView>
144- * );
145- * ...
146- * const styles = StyleSheet.create({
147- * contentContainer: {
148- * paddingVertical: 20
149- * }
150- * });
145+ * ```
146+ * return (
147+ * <ScrollView contentContainerStyle={styles.contentContainer}>
148+ * </ScrollView>
149+ * );
150+ * ...
151+ * const styles = StyleSheet.create({
152+ * contentContainer: {
153+ * paddingVertical: 20
154+ * }
155+ * });
156+ * ```
151157 */
152158 contentContainerStyle : StyleSheetPropType ( ViewStylePropTypes ) ,
153159 /**
@@ -156,8 +162,10 @@ const ScrollView = React.createClass({
156162 * shortcuts `"normal"` and `"fast"` which match the underlying iOS settings
157163 * for `UIScrollViewDecelerationRateNormal` and
158164 * `UIScrollViewDecelerationRateFast` respectively.
159- * - normal: 0.998 (the default)
160- * - fast: 0.99
165+ *
166+ * - `'normal'`: 0.998 (the default)
167+ * - `'fast'`: 0.99
168+ *
161169 * @platform ios
162170 */
163171 decelerationRate : PropTypes . oneOfType ( [
@@ -171,9 +179,11 @@ const ScrollView = React.createClass({
171179 horizontal : PropTypes . bool ,
172180 /**
173181 * The style of the scroll indicators.
174- * - `default` (the default), same as `black`.
175- * - `black`, scroll indicator is black. This style is good against a light background.
176- * - `white`, scroll indicator is white. This style is good against a dark background.
182+ *
183+ * - `'default'` (the default), same as `black`.
184+ * - `'black'`, scroll indicator is black. This style is good against a light background.
185+ * - `'white'`, scroll indicator is white. This style is good against a dark background.
186+ *
177187 * @platform ios
178188 */
179189 indicatorStyle : PropTypes . oneOf ( [
@@ -195,9 +205,10 @@ const ScrollView = React.createClass({
195205 canCancelContentTouches : PropTypes . bool ,
196206 /**
197207 * Determines whether the keyboard gets dismissed in response to a drag.
198- * - 'none' (the default), drags do not dismiss the keyboard.
199- * - 'on-drag', the keyboard is dismissed when a drag begins.
200- * - 'interactive', the keyboard is dismissed interactively with the drag and moves in
208+ *
209+ * - `'none'` (the default), drags do not dismiss the keyboard.
210+ * - `'on-drag'`, the keyboard is dismissed when a drag begins.
211+ * - `'interactive'`, the keyboard is dismissed interactively with the drag and moves in
201212 * synchrony with the touch; dragging upwards cancels the dismissal.
202213 * On android this is not supported and it will have the same behavior as 'none'.
203214 */
@@ -209,14 +220,14 @@ const ScrollView = React.createClass({
209220 /**
210221 * Determines when the keyboard should stay visible after a tap.
211222 *
212- * - ' never' (the default), tapping outside of the focused text input when the keyboard
223+ * - ` never` (the default), tapping outside of the focused text input when the keyboard
213224 * is up dismisses the keyboard. When this happens, children won't receive the tap.
214- * - ' always' , the keyboard will not dismiss automatically, and the scroll view will not
225+ * - ` always` , the keyboard will not dismiss automatically, and the scroll view will not
215226 * catch taps, but children of the scroll view can catch taps.
216- * - ' handled' , the keyboard will not dismiss automatically when the tap was handled by
227+ * - ` handled` , the keyboard will not dismiss automatically when the tap was handled by
217228 * a children, (or captured by an ancestor).
218- * - false, deprecated, use 'never' instead
219- * - true, deprecated, use 'always' instead
229+ * - ` false` , deprecated, use 'never' instead
230+ * - ` true` , deprecated, use 'always' instead
220231 */
221232 keyboardShouldPersistTaps : PropTypes . oneOf ( [ 'always' , 'never' , 'handled' , false , true ] ) ,
222233 /**
@@ -256,7 +267,7 @@ const ScrollView = React.createClass({
256267 */
257268 pagingEnabled : PropTypes . bool ,
258269 /**
259- * When false, the content does not scroll.
270+ * When false, the view cannot be scrolled via touch interaction
260271 * The default value is true.
261272 */
262273 scrollEnabled : PropTypes . bool ,
@@ -308,17 +319,21 @@ const ScrollView = React.createClass({
308319 /**
309320 * When set, causes the scroll view to stop at multiples of the value of
310321 * `snapToInterval`. This can be used for paginating through children
311- * that have lengths smaller than the scroll view. Used in combination
312- * with `snapToAlignment`.
322+ * that have lengths smaller than the scroll view. Typically used in
323+ * combination with `snapToAlignment` and `decelerationRate="fast"`.
324+ * Overrides less configurable `pagingEnabled` prop.
325+ *
313326 * @platform ios
314327 */
315328 snapToInterval : PropTypes . number ,
316329 /**
317330 * When `snapToInterval` is set, `snapToAlignment` will define the relationship
318331 * of the snapping to the scroll view.
319- * - `start` (the default) will align the snap at the left (horizontal) or top (vertical)
320- * - `center` will align the snap in the center
321- * - `end` will align the snap at the right (horizontal) or bottom (vertical)
332+ *
333+ * - `'start'` (the default) will align the snap at the left (horizontal) or top (vertical)
334+ * - `'center'` will align the snap in the center
335+ * - `'end'` will align the snap at the right (horizontal) or bottom (vertical)
336+ *
322337 * @platform ios
323338 */
324339 snapToAlignment : PropTypes . oneOf ( [
@@ -383,6 +398,15 @@ const ScrollView = React.createClass({
383398 'always' ,
384399 'never' ,
385400 ] ) ,
401+ /**
402+ * When true, ScrollView will emit updateChildFrames data in scroll events,
403+ * otherwise will not compute or emit child frame data. This only exists
404+ * to support legacy issues, `onLayout` should be used instead to retrieve
405+ * frame data.
406+ * The default value is false.
407+ * @platform ios
408+ */
409+ DEPRECATED_sendUpdatedChildFrames : PropTypes . bool
386410 } ,
387411
388412 mixins : [ ScrollResponder . Mixin ] ,
@@ -490,24 +514,30 @@ const ScrollView = React.createClass({
490514 this . scrollTo ( { x, y, animated : false } ) ;
491515 } ,
492516
517+ /**
518+ * Displays the scroll indicators momentarily.
519+ *
520+ * @platform ios
521+ */
522+ flashScrollIndicators : function ( ) {
523+ this . getScrollResponder ( ) . scrollResponderFlashScrollIndicators ( ) ;
524+ } ,
525+
493526 _getKeyForIndex : function ( index , childArray ) {
494527 const child = childArray [ index ] ;
495528 return child && child . key ;
496529 } ,
497530
498531 _updateAnimatedNodeAttachment : function ( ) {
532+ if ( this . _scrollAnimatedValueAttachment ) {
533+ this . _scrollAnimatedValueAttachment . detach ( ) ;
534+ }
499535 if ( this . props . stickyHeaderIndices && this . props . stickyHeaderIndices . length > 0 ) {
500- if ( ! this . _scrollAnimatedValueAttachment ) {
501- this . _scrollAnimatedValueAttachment = Animated . attachNativeEvent (
502- this . _scrollViewRef ,
503- 'onScroll' ,
504- [ { nativeEvent : { contentOffset : { y : this . _scrollAnimatedValue } } } ]
505- ) ;
506- }
507- } else {
508- if ( this . _scrollAnimatedValueAttachment ) {
509- this . _scrollAnimatedValueAttachment . detach ( ) ;
510- }
536+ this . _scrollAnimatedValueAttachment = Animated . attachNativeEvent (
537+ this . _scrollViewRef ,
538+ 'onScroll' ,
539+ [ { nativeEvent : { contentOffset : { y : this . _scrollAnimatedValue } } } ]
540+ ) ;
511541 }
512542 } ,
513543
@@ -572,8 +602,8 @@ const ScrollView = React.createClass({
572602 this . _scrollViewRef = ref ;
573603 } ,
574604
575- _innerViewRef : ( null : ?View ) ,
576- _setInnerViewRef : function ( ref : ?View ) {
605+ _innerViewRef : ( null : ?NativeMethodsMixinType ) ,
606+ _setInnerViewRef : function ( ref : ?NativeMethodsMixinType ) {
577607 this . _innerViewRef = ref ;
578608 } ,
579609
@@ -583,6 +613,10 @@ const ScrollView = React.createClass({
583613 if ( Platform . OS === 'ios' ) {
584614 ScrollViewClass = RCTScrollView ;
585615 ScrollContentContainerViewClass = RCTScrollContentView ;
616+ warning (
617+ ! this . props . snapToInterval || ! this . props . pagingEnabled ,
618+ 'snapToInterval is currently ignored when pagingEnabled is true.'
619+ ) ;
586620 } else if ( Platform . OS === 'android' ) {
587621 if ( this . props . horizontal ) {
588622 ScrollViewClass = AndroidHorizontalScrollView ;
@@ -656,7 +690,13 @@ const ScrollView = React.createClass({
656690 { ...contentSizeChangeProps }
657691 ref = { this . _setInnerViewRef}
658692 style = { contentContainerStyle}
659- removeClippedSubviews = { this. props . removeClippedSubviews }
693+ removeClippedSubviews = {
694+ // Subview clipping causes issues with sticky headers on Android and
695+ // would be hard to fix properly in a performant way.
696+ Platform. OS === 'android' && hasStickyHeaders ?
697+ false :
698+ this . props . removeClippedSubviews
699+ }
660700 collapsable = { false } >
661701 { children}
662702 < / S c r o l l C o n t e n t C o n t a i n e r V i e w C l a s s > ;
@@ -671,6 +711,10 @@ const ScrollView = React.createClass({
671711 this . props . alwaysBounceVertical :
672712 ! this . props . horizontal ;
673713
714+
715+ const DEPRECATED_sendUpdatedChildFrames =
716+ ! ! this . props . DEPRECATED_sendUpdatedChildFrames ;
717+
674718 const baseStyle = this . props . horizontal ? styles . baseHorizontal : styles . baseVertical ;
675719 const props = {
676720 ...this . props ,
@@ -699,6 +743,7 @@ const ScrollView = React.createClass({
699743 scrollEventThrottle : hasStickyHeaders ? 1 : this . props . scrollEventThrottle ,
700744 sendMomentumEvents : ( this . props . onMomentumScrollBegin || this . props . onMomentumScrollEnd ) ?
701745 true : false ,
746+ DEPRECATED_sendUpdatedChildFrames
702747 } ;
703748
704749 const { decelerationRate } = this . props ;
@@ -795,6 +840,7 @@ if (Platform.OS === 'android') {
795840 ( ScrollView : ReactClass < any > ) ,
796841 nativeOnlyProps ,
797842 ) ;
843+ // $FlowFixMe (bvaughn) Update ComponentInterface in ViewPropTypes to include a string type (for Fiber host components) in a follow-up.
798844 RCTScrollContentView = requireNativeComponent ( 'RCTScrollContentView' , View ) ;
799845}
800846
0 commit comments