7
7
LayoutChangeEvent ,
8
8
} from 'react-native'
9
9
import { FlashList , ListRenderItemInfo } from '@shopify/flash-list'
10
- import Animated , { runOnJS , useAnimatedScrollHandler , useSharedValue } from 'react-native-reanimated'
10
+ import Animated , { runOnJS , useAnimatedScrollHandler , useAnimatedStyle , useSharedValue , withTiming } from 'react-native-reanimated'
11
11
import { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes'
12
12
import DayAnimated from './components/DayAnimated'
13
13
import Item from './components/Item'
@@ -38,7 +38,7 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
38
38
listViewProps,
39
39
invertibleScrollViewProps,
40
40
extraData = null ,
41
- scrollToBottom = false ,
41
+ isScrollToBottomEnabled = false ,
42
42
scrollToBottomOffset = 200 ,
43
43
alignTop = false ,
44
44
scrollToBottomStyle,
@@ -52,7 +52,12 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
52
52
scrollToBottomComponent : scrollToBottomComponentProp ,
53
53
} = props
54
54
55
+ const scrollToBottomOpacity = useSharedValue ( 0 )
55
56
const [ isScrollToBottomVisible , setIsScrollToBottomVisible ] = useState ( false )
57
+ const scrollToBottomStyleAnim = useAnimatedStyle ( ( ) => ( {
58
+ opacity : scrollToBottomOpacity . value ,
59
+ } ) , [ scrollToBottomOpacity ] )
60
+
56
61
const [ hasScrolled , setHasScrolled ] = useState ( false )
57
62
58
63
const daysPositions = useSharedValue < DaysPositions > ( { } )
@@ -105,21 +110,33 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
105
110
layoutMeasurement : { height : layoutMeasurementHeight } ,
106
111
} = event
107
112
108
- if ( inverted )
109
- if ( contentOffsetY > scrollToBottomOffset ! )
113
+ const duration = 250
114
+
115
+ if ( inverted ) {
116
+ if ( contentOffsetY > scrollToBottomOffset ! ) {
110
117
setIsScrollToBottomVisible ( true )
111
- else
112
- setIsScrollToBottomVisible ( false )
113
- else if (
118
+ scrollToBottomOpacity . value = withTiming ( 1 , { duration } )
119
+ } else {
120
+ scrollToBottomOpacity . value = withTiming ( 0 , { duration } , isFinished => {
121
+ if ( isFinished )
122
+ runOnJS ( setIsScrollToBottomVisible ) ( false )
123
+ } )
124
+ }
125
+ } else if (
114
126
contentOffsetY < scrollToBottomOffset ! &&
115
127
contentSizeHeight - layoutMeasurementHeight > scrollToBottomOffset !
116
- )
128
+ ) {
117
129
setIsScrollToBottomVisible ( true )
118
- else
119
- setIsScrollToBottomVisible ( false )
130
+ scrollToBottomOpacity . value = withTiming ( 1 , { duration } )
131
+ } else {
132
+ scrollToBottomOpacity . value = withTiming ( 0 , { duration } , isFinished => {
133
+ if ( isFinished )
134
+ runOnJS ( setIsScrollToBottomVisible ) ( false )
135
+ } )
136
+ }
120
137
121
138
setHasScrolled ( true )
122
- } , [ handleOnScrollProp , inverted , scrollToBottomOffset ] )
139
+ } , [ handleOnScrollProp , inverted , scrollToBottomOffset , scrollToBottomOpacity ] )
123
140
124
141
const handleLayoutDayWrapper = useCallback ( ( ref : unknown , id : string | number , createdAt : number ) => {
125
142
setTimeout ( ( ) => { // do not delete "setTimeout". It's necessary for get correct layout.
@@ -219,17 +236,27 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
219
236
} , [ scrollToBottomComponentProp ] )
220
237
221
238
const renderScrollToBottomWrapper = useCallback ( ( ) => {
239
+ if ( ! isScrollToBottomVisible )
240
+ return null
241
+
222
242
return (
223
- < View style = { [ stylesCommon . centerItems , styles . scrollToBottomStyle , scrollToBottomStyle ] } >
243
+ < Animated . View
244
+ style = { [
245
+ stylesCommon . centerItems ,
246
+ styles . scrollToBottomStyle ,
247
+ scrollToBottomStyle ,
248
+ scrollToBottomStyleAnim ,
249
+ ] }
250
+ >
224
251
< TouchableOpacity
225
252
onPress = { ( ) => doScrollToBottom ( ) }
226
253
hitSlop = { { top : 5 , left : 5 , right : 5 , bottom : 5 } }
227
254
>
228
255
{ renderScrollBottomComponent ( ) }
229
256
</ TouchableOpacity >
230
- </ View >
257
+ </ Animated . View >
231
258
)
232
- } , [ scrollToBottomStyle , renderScrollBottomComponent , doScrollToBottom ] )
259
+ } , [ scrollToBottomStyle , renderScrollBottomComponent , doScrollToBottom , scrollToBottomStyleAnim , isScrollToBottomVisible ] )
233
260
234
261
const onLayoutList = useCallback ( ( event : LayoutChangeEvent ) => {
235
262
listHeight . value = event . nativeEvent . layout . height
@@ -299,7 +326,7 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
299
326
{ ...listViewProps }
300
327
onLayout = { onLayoutList }
301
328
/>
302
- { isScrollToBottomVisible && scrollToBottom
329
+ { isScrollToBottomEnabled
303
330
? renderScrollToBottomWrapper ( )
304
331
: null }
305
332
< DayAnimated
0 commit comments