@@ -3,14 +3,14 @@ import {isFunction, isUndefined} from 'lodash';
3
3
import React , { useCallback , useRef , useMemo , useEffect , useState } from 'react' ;
4
4
import { TextStyle , ViewStyle , FlatList , NativeSyntheticEvent , NativeScrollEvent , StyleSheet } from 'react-native' ;
5
5
import Animated , { useSharedValue , useAnimatedScrollHandler } from 'react-native-reanimated' ;
6
+ import { Constants } from 'helpers' ;
6
7
import { Colors , Spacings } from 'style' ;
8
+ import { asBaseComponent } from '../../commons/new' ;
7
9
import View from '../../components/view' ;
8
10
import Fader , { FaderPosition } from '../../components/fader' ;
9
- import { Constants } from 'helpers' ;
10
11
import Item , { ItemProps } from './Item' ;
11
- import usePresenter from './usePresenter' ;
12
12
import Text , { TextProps } from '../../components/text' ;
13
- import { asBaseComponent } from '../../commons/new ' ;
13
+ import usePresenter from './usePresenter ' ;
14
14
15
15
const AnimatedFlatList = Animated . createAnimatedComponent ( FlatList ) ;
16
16
@@ -125,26 +125,46 @@ const WheelPicker = ({
125
125
preferredNumVisibleRows : numberOfVisibleRows
126
126
} ) ;
127
127
128
+ const prevInitialValue = useRef ( initialValue ) ;
128
129
const prevIndex = useRef ( currentIndex ) ;
129
130
const [ scrollOffset , setScrollOffset ] = useState ( currentIndex * itemHeight ) ;
130
131
const [ flatListWidth , setFlatListWidth ] = useState ( 0 ) ;
131
132
const keyExtractor = useCallback ( ( item : ItemProps , index : number ) => `${ item } .${ index } ` , [ ] ) ;
132
133
133
- /* This effect enforce the index to be controlled by selectedValue passed by the user */
134
134
useEffect ( ( ) => {
135
+ // This effect enforce the index to be controlled by selectedValue passed by the user
135
136
if ( shouldControlComponent ( scrollOffset ) ) {
136
137
scrollToIndex ( currentIndex , true ) ;
137
138
}
138
139
} ) ;
139
140
140
- /* This effect making sure to reset index if initialValue has changed */
141
141
useEffect ( ( ) => {
142
+ // This effect making sure to reset index if initialValue has changed
142
143
! isUndefined ( initialValue ) && scrollToIndex ( currentIndex , true ) ;
143
144
} , [ currentIndex ] ) ;
144
145
145
- const scrollToPassedIndex = useCallback ( ( ) => {
146
- scrollToIndex ( currentIndex , false ) ;
147
- } , [ ] ) ;
146
+ const _onChange = useCallback ( ( value : string | number , index : number ) => {
147
+ if ( prevInitialValue . current !== initialValue ) {
148
+ // don't invoke 'onChange' if 'initialValue' changed
149
+ prevInitialValue . current = initialValue ;
150
+ } else {
151
+ onChange ?.( value , index ) ;
152
+ }
153
+ } , [ initialValue , onChange ] ) ;
154
+
155
+ const onValueChange = useCallback ( ( event : NativeSyntheticEvent < NativeScrollEvent > ) => {
156
+ setScrollOffset ( event . nativeEvent . contentOffset . y ) ;
157
+ const { index, value} = getRowItemAtOffset ( event . nativeEvent . contentOffset . y ) ;
158
+ _onChange ( value , index ) ;
159
+ } , [ _onChange , getRowItemAtOffset ] ) ;
160
+
161
+ const onMomentumScrollEndAndroid = ( index : number ) => {
162
+ // handle Android bug: ScrollView does not call 'onMomentumScrollEnd' when scrolled programmatically (https://github.com/facebook/react-native/issues/26661)
163
+ if ( Constants . isAndroid && prevIndex . current !== index ) {
164
+ prevIndex . current = index ;
165
+ _onChange ( items ?. [ index ] ?. value , index ) ;
166
+ }
167
+ } ;
148
168
149
169
const scrollToOffset = ( index : number , animated : boolean ) => {
150
170
// TODO: we should remove this split (the getNode section) in V6 and remove support for reanimated 1
@@ -159,35 +179,17 @@ const WheelPicker = ({
159
179
} ;
160
180
161
181
const scrollToIndex = ( index : number , animated : boolean ) => {
162
- // this is done to handle onMomentumScrollEnd not being called in Android:
163
- // https://github.com/facebook/react-native/issues/26661
164
- if ( Constants . isAndroid && prevIndex . current !== index ) {
165
- prevIndex . current = index ;
166
- onChange ?.( items ?. [ index ] ?. value , index ) ;
167
- }
182
+ onMomentumScrollEndAndroid ( index ) ;
168
183
setTimeout ( ( ) => scrollToOffset ( index , animated ) , 100 ) ;
169
184
} ;
170
185
186
+ const scrollToPassedIndex = useCallback ( ( ) => {
187
+ scrollToIndex ( currentIndex , false ) ;
188
+ } , [ ] ) ;
189
+
171
190
const selectItem = useCallback ( index => {
172
191
scrollToIndex ( index , true ) ;
173
- } ,
174
- [ itemHeight ] ) ;
175
-
176
- const onValueChange = useCallback ( ( event : NativeSyntheticEvent < NativeScrollEvent > ) => {
177
- setScrollOffset ( event . nativeEvent . contentOffset . y ) ;
178
-
179
- const { index, value} = getRowItemAtOffset ( event . nativeEvent . contentOffset . y ) ;
180
- onChange ?.( value , index ) ;
181
- } ,
182
- [ onChange ] ) ;
183
-
184
- const alignmentStyle = useMemo ( ( ) => {
185
- return align === WheelPickerAlign . RIGHT
186
- ? { alignSelf : undefined }
187
- : align === WheelPickerAlign . LEFT
188
- ? { alignSelf : 'flex-start' }
189
- : { alignSelf : 'center' } ;
190
- } , [ align ] ) ;
192
+ } , [ itemHeight ] ) ;
191
193
192
194
const renderItem = useCallback ( ( { item, index} ) => {
193
195
return (
@@ -207,17 +209,33 @@ const WheelPicker = ({
207
209
testID = { `${ testID } .item_${ index } ` }
208
210
/>
209
211
) ;
210
- } ,
211
- [ itemHeight ] ) ;
212
+ } , [ itemHeight ] ) ;
212
213
213
- const separators = useMemo ( ( ) => {
214
- return (
215
- < View absF centerV pointerEvents = "none" >
216
- < View style = { styles . separators } />
217
- </ View >
218
- ) ;
214
+ const getItemLayout = useCallback ( ( _data , index : number ) => {
215
+ return { length : itemHeight , offset : itemHeight * index , index } ;
216
+ } , [ itemHeight ] ) ;
217
+
218
+ const updateFlatListWidth = useCallback ( ( width : number ) => {
219
+ setFlatListWidth ( width ) ;
219
220
} , [ ] ) ;
220
221
222
+ const alignmentStyle = useMemo ( ( ) => {
223
+ return align === WheelPickerAlign . RIGHT
224
+ ? { alignSelf : undefined }
225
+ : align === WheelPickerAlign . LEFT
226
+ ? { alignSelf : 'flex-start' }
227
+ : { alignSelf : 'center' } ;
228
+ } , [ align ] ) ;
229
+
230
+ const contentContainerStyle = useMemo ( ( ) => {
231
+ return [
232
+ {
233
+ paddingVertical : height / 2 - itemHeight / 2
234
+ } ,
235
+ alignmentStyle
236
+ ] ;
237
+ } , [ height , itemHeight , alignmentStyle ] ) ;
238
+
221
239
const labelContainerStyle = useMemo ( ( ) => {
222
240
return [ { position : 'absolute' , top : 0 , bottom : 0 } , alignmentStyle ] ;
223
241
} , [ alignmentStyle ] ) ;
@@ -237,26 +255,15 @@ const WheelPicker = ({
237
255
238
256
const fader = useMemo ( ( ) => ( position : FaderPosition ) => {
239
257
return < Fader visible position = { position } size = { 60 } /> ;
240
- } ,
241
- [ ] ) ;
242
-
243
- const getItemLayout = useCallback ( ( _data , index : number ) => {
244
- return { length : itemHeight , offset : itemHeight * index , index} ;
245
- } ,
246
- [ itemHeight ] ) ;
247
-
248
- const updateFlatListWidth = useCallback ( ( width : number ) => {
249
- setFlatListWidth ( width ) ;
250
258
} , [ ] ) ;
251
259
252
- const contentContainerStyle = useMemo ( ( ) => {
253
- return [
254
- {
255
- paddingVertical : height / 2 - itemHeight / 2
256
- } ,
257
- alignmentStyle
258
- ] ;
259
- } , [ height , itemHeight , alignmentStyle ] ) ;
260
+ const separators = useMemo ( ( ) => {
261
+ return (
262
+ < View absF centerV pointerEvents = "none" >
263
+ < View style = { styles . separators } />
264
+ </ View >
265
+ ) ;
266
+ } , [ ] ) ;
260
267
261
268
return (
262
269
< View testID = { testID } bg-white style = { style } >
0 commit comments