I have a ScrollView (actually Animated.ScrollView) that I'd like to decide whether to allow vertically scroll or not on scroll start, based on some states of inner components. I know there is a scrollEnabled property which works but the scroll view contains some components that that a few frames to render and changing scrollEnabled property based on inner views' interactions cause a re-render, which drops a few frames and because of the nature of my app needing to change this property based on some animation/smooth scrolling of the inner views, those dropped frames cause a negative user experience.
I've also tried preventDefault of the scroll begin drag event but nothing changed (it allows scrolling regardless of I call it or not).
How can I decide whether or not to allow scrolling of scroll view dynamically on scroll start without a state/props update (which causes a re-render of an expensive view tree, dropping frames)? Something like pan responder's onMoveShouldSetPanResponder[Capture] events might be of great help but returning false from them just don't work (it captures and scrolls regardlessly even though they are called). (I'm on React Native 0.64)
After reading the post in https://codedaily.io/courses/Master-React-Native-Animations/Using-and-Understanding-setNativeProps I solved it by setting native props on scroll view (that I reference directly using a ref) instead of updating state, preventing a re-render:
this.state.scrollView.current?.setNativeProps({
scrollEnabled: false
});
Related
I am using React Native's FlatList component with pagination. I want to execute a callback with the destination page as a parameter whenever the user releases on scroll.
onScroll fires pre-maturely and switches pages before the users releases the screen.
onScrollDragEnd doesn't correctly give you the destination page unless you drag your finger at least half way across the screen (eg doesn't work if you do a quick swipe).
onMomentScrollEnd doesn't get fired until the display stops moving, which may not get fired if the user is constantly swiping.
Is there some sort of middle ground to achieve this functionality?
I watched this presentation and there's a section on how to build an IOS Maps like UI. When dragging from the bottom to top, it drags to the top, and after it reaches the top, it continues scrolling up. Also, when scrolling down, when it reached the top content of the ScrollView, it continues to drag down.
It is suggested that it can be done using ScrollView by adding an empty transparent cell as the first element on the ScrollView. I have tried implementing the same which can be found in this snack. In my case, instead of Maps, I am using another ScrollView.
But the problem is that the first element (transparent element) does not allow to interact with the First ScrollView elements. I have tried with pointerEvents inside the first transparent view and even in its parent ScrollView. But this does not help. Has anyone tried implementing this kind of use case with react-native? All I found was this library, but I think it's not maintained properly.
you need to set the z-index of the transparent view to send it under/behind the interactive content, here is a good resource:
https://philipwalton.com/articles/what-no-one-told-you-about-z-index/
Edit: Actually I could not accomplish it, it seems like everything inside a scrollview will always be behind or in front of other elements, it seems like you can't have part of the scrollview behind something else and another part in front of something else.
I have a react-native SectionList that contains multiple FlatLists in the view. When a user touches one of the elements in the bottom FlatList, some of the FlatLists above will load new data causing the user's current view to seem be pushed up. In other words, the user's y-position remains the same but the content that was previously in view now has a greater y-position.
How can I keep the user's y-position in sync with the elements they had in view before the elements in the other FlatLists above were added?
It is hard to answer without any code example.
Seems scrollToLocation method with animated: false after data was changed should do the trick.
I'm attempting to create a custom NavBar on a screen that renders a ScrollView. Inside the NavBar, there's a button, that when pressed, causes the NavBar to translate downwards, thereby giving the appearance that the NavBar is expanding (This is done using Animated.spring() with the useNativeDriver option). Everything is working great, except if the ScrollView is still scrolling at the time the button is tapped (ie: when "momentum" scroll is taking place). In this scenario, the onPress handler that kicks off the NavBar animation is invoked as expected, but calls to Animated.spring() do not cause any animation to take place. Is it possible to either have the NavBar "expansion" animation to occur during the scroll, or pause the scroll to allow animation to proceed?
Like it's explained in RN docs the animation type you using are stoped by gesture events like scrolling, better use Animated.event() with onScrollprops combined with an interpolation animation to animate you footer.
I would like to create a carousel that scrolls automatically until the user scrolls / touches the ScrollView itself.
The auto-scrolling itself works fine with using scrollView.scrollTo but how could I detect if the user is interacting with the ScrollView? I took a look at the onScroll event but this does not seem to distinct between a user generated event and an event that was generated by calling scrollTo.
Also I'd like to know if it is possible to get the current scroll position from the ScrollView directly instead of reading it everytime from the onScroll event.
I'm very thankful for any tips and suggestions.
By digging into ScrollView's source code you can notice a few undocumented callbacks that will help you achieve what you're after, namely onTouchStart and onTouchEnd. These two callbacks are triggered only when user interacts with the ScrollView and not when you scroll programmatically.
You will probably want to clear your auto-scroll interval on onTouchStart and restart it after a delay on onTouchEnd.
Regarding your next question, the answer is no. As far as I know, no getter is currently exposed to retrieve the current scroll position. Therefore, you need to rely on the event passed to onScroll, retrieve event.nativeEvent.contentOffset['x' or 'y'], and store it in your component's state.
Note that if you're doing some heavy animations that need to follow scroll position closely (e.g. animated header or parallax image), it would be a good idea to use the native driver for Animated.event. You can learn more about it on React Native's blog.