Prevent pull-to-refresh for ScrollView in react-native - react-native

Is there a way to prevent pull-to-refresh functionality for ScrollView component?
I want to be able scroll, but I don't wanna allow to pull down content of component and prevent situations like this:

You seem like you have placed the View containing you custom made action bar inside the scroll view, and what's happening in the image you provided isn't caused by pull-to-refresh it's provided by overscrolling so you got 2 solutions:
1-Place your action bar outside your ScrollView and make the action bar and the ScrollView childrens of 1 View.
2-Add alwaysBounceVertical={false} to your ScrollView props.
Hope this helps.

use a const refreshing = false , initially. Then on call of _onRefresh , change refreshing from false to true, and reinitialise the content of the scollview.

Related

How can I use react-native-gesture-handler to handle react-native-skia touches inside a ScrollView?

I have a ScrollView containing several graphs made with react-native-skia. The graphs are interactable, i.e. I can touch them and move an indicator on the graph along the x-axis of the graph.
My issue is that the whenever the ScrollView events fire (i.e. we scroll up/down), then the graph touch events are ignored which makes for bad UX.
Demo:
Here's a Snack with a reproducible demo: https://snack.expo.dev/#jorundur/supportive-raisins
FYI: For some reason for me the Canvas disappears after 1 second in the Snack, but if you make any change in the file and save (such add a newline somewhere), then it appears. It's fine if you run this locally. But that's some other problem we can ignore for the purpose of this discussion.
Description:
The demo is a react-native ScrollView large enough to make sure we have to scroll, the top component is a graph using react-native-skia. If we drag the cursor in the graph around, then the UX gets bad pretty quickly as the graph touch events seem to be ignored as soon as any vertical scrolling happens. I've tried playing around with ScrollView from react-native-gesture-handler but without luck.
To me, the expected behaviour would be for the graph to be interactable even while scrolling. I.e. if I'm pressing the graph and move my finger diagonally up/down I would expect the ScrollView to scroll and the graph cursor also to change its position accordingly. (I say diagonally since a straight vertical movement wouldn't change the cursor position in this graph.)
Much appreciated if anyone has any ideas on how to solve this! I couldn't work out how to do it via GestureDetector from react-native-gesture-handler like I've heard suggested.
Possible solution (?):
What I think I need to do is remove the onTouch={touchHandler} which I'm using currently in the react-native-skia Canvas component and instead get those touches via gesture detection from react-native-gesture-handler. I then need to make those gestures work simultaneously with the parent ScrollViews scroll event gestures. I've not had any luck implementing that unfortunately.
The solution was to do the following:
Don't use onTouch on Canvas, instead detect gestures via react-native-gesture-handler
Create a gesture and add a ref to it
Add the simultaneousHandlers prop to the ScrollView and use the ref there
This tells the ScrollView that its events should not be blocked by the touch events from the ref
To reiterate, what I wanted to do was to have the touch events of a ScrollView work simultaneously with touch events from a react-native-skia Canvas child component.
Code (relevant bits):
import * as React from 'react';
import {
GestureHandlerRootView,
ScrollView // Note that this is not imported from react-native
} from 'react-native-gesture-handler';
const App = () => {
// Create ref for the ScrollView to know what other gestures it should work simultaneously with.
// My use case required pan but this can be swapped for other gestures.
const panGestureRef = React.useRef<GestureType>(Gesture.Pan());
// The logic that used to be in `onTouch` on the Canvas is now here
const panGesture = Gesture.Pan()
.onChange((e) => {
// Do stuff, also use the other callbacks available as needed
})
.withRef(panGestureRef);
return (
<GestureHandlerRootView style={{ flex: 1 }}>{/* Don't forget this! It should be at the root of your project. */}
<ScrollView simultaneousHandlers={[panGestureRef]}>
<GestureDetector gesture={panGesture}>
<Canvas style={{ width: 200, height: 200 }}>
{/* Your interactive react-native-skia magic */}
</Canvas>
</GestureDetector>
</ScrollView>
</GestureHandlerRootView>
);
};
export default App;

React Native - Set parent match width for component inside a ScrollView that is inside a Modal

I have a Modal with a ScrollView inside and some items inside the ScrollView. When the Modal popped up, the item's border is not aligned to the Modal's border. Some components like TextInput become thinner and some is overflow. It's not like this outside of Modal.
This can be solved by setting component's offset explicitly relative to Dimensions.get('window').width. But I just want an implicit solution.
I've done trying setting style properties for ScrollView's contentContainerStyle and also putting a wrapper View inside the ScrollView. None of them works.
I've made it after wrap ScrollView with a View with style flexDirection : 'row'. Yet to figure out why

Modal in front of a modal in react native, not picking up state

I am using the Modal component from react-native to creat a slide up menu for users to select. The issue with this is, if you wish to dim the background and animate with 'slide', it does this ugly thing of sliding a dimmed box up the screen, instead of dimming the whole background THEN sliding the view in.
So I tried to solve for this by using two Modals. One modal for the dark background to fade in and second modal to slide in with the menu with a transparent background.
This actually works, but when this.doneDayPicker changes the state of this.state.showModalDayPicker so both modals are no longer visible, <DarkModal> still appears. I'm left with <DarkModal> permanently on the screen.
What can I change to let <DarkModal> dissapear when this.state.showModalDayPicker is changed?
return (
<DarkModal visible={this.state.showModalDayPicker}>
<GoalModalScreen
visible={this.state.showModalDayPicker}
done={this.doneDayPicker}
title='Health benefits'
height={this.state.goalModalHeight}
>
{this.flatList()}
</GoalModalScreen>
</DarkModal>
);
Initially I would say this is because there is no done property on DarkModal like goalModalScreen?
Or use a Ternary Operator
{this.state.showModalDayPicker ? <DarkModal> : undefined}
You might also setup DarkModal's own toggle in state.
{this.state.toggleDarkModal ? <DarkModal> : undefined}

Setting an initial scroll position of a React Native ListView

I'm trying to set the initial scroll position of a ListView in react native.
Right now, I'm doing this:
componentDidMount() {
let i = this.props.images.indexOf(this.props.current);
if(i != -1) {
this.refs.listView.scrollTo({ x:i*this.props.width, y:0, animated:false });
}
}
where the images prop is the datasource for the ListView, the current prop is where I want to be initially scrolled to, and the width prop is the width of the component. (The component scrolls horizontally).
This works, but there's a delay between the initial render and the call to componentDidMount, giving me a flash of the end of end of the list before the list is scrolled.
Is there a way of setting an initial scroll position of the list? Or better way of doing this to get rid of that flash?
On iOS you can use the ScrollView#contentOffset to set the initial scroll position of a ListView, which inherits the properties of ScrollView.
If you are looking for an Android solution, the ListView.scrollTo method you are calling seems like the best bet for the general case.
That said, if I interpret your code sample correctly, you are using the ListView for a paginated, horizontal list, perhaps with the help of the pagingEnabled property? If this is the case, on Android you might look at using ViewPagerAndroid instead, and setting the initialPage property.

React Native NavigatorExperimental - Combine AnimatedView with CardStack

i 've a NavigationAnimatedView which rendering a ListView with pushed DetailsView.
In the NavigationHeader, on the rightComponent, i have a button and i want to display a view with NavigationCardStack from bottomToTop. How can i combine the two modes of navigation ?
Like the filters button on the F8 app on the home screen.
i don't understand how with a dispatch action (navigatePush ?) on the FiltersButton, i can't switch with a navigationCardStack to display a FilterViews from BottomToTop.
You can provide props to NavigationCard when you render it:
_renderScene(props) {
return (
<NavigationCard
style={NavigationCardStackStyleInterpolator.forVertical(props)}
...
Sorry that part isn't documented very well right now!