React/React Native onLayout for Child View - javascript

I am looking to build a button/view that animates when a user taps and holds on it. This animation will just be a progressive change of color from white to a green color. I have found a tutorial that does exactly this:
http://browniefed.com/blog/react-native-press-and-hold-button-actions/
In the render function, the author uses:
<View style={styles.container} onLayout={this.onPageLayout}>
<TouchableWithoutFeedback
onPressIn={this.handlePressIn}
onPressOut={this.handlePressOut}
>
<View style={styles.button} onLayout={this.onPageLayout2}>
<Animated.View style={[styles.bgFill, this.getProgressStyles()]} />
<Text style={styles.text}>Press And Hold Me</Text>
</View>
</TouchableWithoutFeedback>
<View>
<Text>{this.state.textComplete}</Text>
</View>
</View>
Please note there are two onLayout mentions...one in the parent View and the other in the View about halfway down
The way this works is the onLayout call is supposed to get the size of the TouchableWithoutFeedback button so that I can set the animation to have the correct sizing. However, the second onLayout call just does not get called no matter what I try. The very top View's onLayout is being called so I know that my code is good (as this.onPageLayout and this.onPageLayout2 are exact copies except their console.logs vary slightly).
If I remove all the surrounding code and only have the inner View in this render function, then the onLayout={this.onPageLayout2} works like a charm, but as soon as I put the rest of the parent back in, it no longer works.
Does anybody know how I can get a child View to have their onLayout method work? Or another way or getting the size of the TouchableWithoutFeedback button for my purposes of animation?
Thanks!

You are using TouchableWithoutFeedback and so you don't get any feedback from it's child. Change it to other buttons for example: TouchableOpacity, Then you can have onLayout for both components.

Related

How can you make a screen with a FlatList scrollable in React Native?

One of my screens has a FlatList, but it also features a TextInput that must remain at the top of the page. The TextInput determines which other component is rendered, if it's empty it is a category page but if it's filled with any text it's the search results. My problem right now is that I have the TextInput outside of the main FlatList, and this causes it to be at the top of the screen even when scrolling the list. I'd like for it to remain at the top of the page and not follow the scroll.
If I put the TextInput inside one of the FlatLists it causes the other to not have it due to rendering separate components. But if I place it in both FlatLists it creates a bug where after typing the first character the TextInput will exit the editing mode since a completely new component is being rendered.
Here's the structure I have right now:
<View>
<TextInput />
<View>
{conditional check ? (
<FlatList /> :
(<View>
<FlatList />
</View>
}
So how docs says FlatList has a props called ListHeaderComponent to display at the top of the list a component. https://reactnative.dev/docs/flatlist
//textinput component
const input = () => {
<View>
<TextInput />
</View>
};
<FlatList
listHeaderComponent={input}
data={/* data or another type of array */}
renderItem={ /* put here what you want to be scrollable */ }
/>
If I understood it correctly that if you want to scroll TextInput with the list, you should wrap the TextInput and all inside ScrollView and instead of using FlatList, map the data to be rendered and pass it to child component like below.
<ScrollView>
<TextInput />
{conditional check ? (
{data1.map((item,index)=> <ChildComponent1/> //renderItem in FlatList 1
)}):
(<View>
{data2.map((item,index)=> <ChildComponent2/> //renderItem in FlatList 2
)}
</View>)
}
<ScrollView>

How can I reveal an element behind a flatlist and have it interactable in React Native?

I am trying to render an element that is positioned absolutely behind a flatlist and it will be revealed once the user scrolls to the bottom. The issue I am facing is that the element needs to be interactable, and the flatlist root element takes all pointerevents instead of the background element.
const FlatlistOverElement: FC = () => (
<View style={{ flex: 1, width: '100%' }}>
<FlatList
data={data}
style={{ flexGrow: 1 }}
ListFooterComponent={() => (
<View style={{ height: BACKGROUND_ELEMENT_HEIGHT, opacity: 0 }} />
)}
renderItem={RenderItem}
/>
<AbsolutelyPositionedElementBehindFlatList />
</View>
)
I have tried to remove pointerevents from the flatlist, then the flatlist is not scrollable.
I have tried to set the height of the flatlist smaller, and let the content overflow. This allows the user to interact with the element, but for that part of the screen, the user can not scroll the flatlist.
What other approach can I utilise in order to solve this issue ?
You can use zIndex property on the scroll completion. Just provide a higher zIndex value than that of FlatList to absolute component whenever the scroll is completed.
zIndex Layout Props
Thanks for the suggestions. I ended up using a zIndex to put the interactable content in front of the flatlist when having scrolled to the end, as well as adding snap points on both sides of the element. To prevent the user from half revealing the element and not be able to interact with it.

How to go to top of the screen with ref react native

how can i go to the top of the screen or other element in the screen with react-native ?
i need to use ref for that ?
note that i have scroll view from outside, so i Cant use scroll view methods
little of my code:
<AnimatedButton
onPress={() => console.log("check", myref.current)}
icon="arrow-up"
/>
)}
and i want to go for example to the first element in the screen:
<View ref={myref}>
<Text style={styles.massagetitle}>בחר סוג טיפול</Text>
</View>
how to handle that without scrollView ?? (again, because i cant put scroll view because i have scroll view from outside wrap it)

React Native ScrollView above another ScrollView

I am trying to make something similar to the Instagram ScrollView which is inside the "Search" screen of the app. If you are using iOS and see the app, you will see that when you start typing the username of an user, a ScrollView overlaps the feed ScrollView.
For this I am doing:
<ScrollView>
<HorizontalStoriesList />
...
<Animated.ScrollView
testID="SearchUsersList"
style={[
StyleSheet.absoluteFill,
{
opacity: searchUsersListOpacity,
backgroundColor: colors.white,
},
]}
>
<UsersList data={data} />
</Animated.ScrollView>
</ScrollView>
My problem is that the ScrollView which is more above doesn't have the good height, instead of using its own height it uses the height of the parent scroll view. Also, I am not able to touch the components that are behind this scrollview (The HorizontalStoriesList, for example. I have tried with pointerEvents="none" but this make the Animated Scroll View (the one which is more above) to be untouchable.
Any ideas how to solve this?
Thank you.

How to only render a view when an image inside of it has finished rendering, while showing a rendering indicator?

Let's say we have this block of code:
<View>
<Image
source={{uri: this.props.image}}
renderIndicator={() => <SimpleLoader />}
/>
<Text>{this.props.title}</Text>
</View>
It currently shows a rendering animation on the image, but shows the View as well as text, and then eventually renders the image.
I would like to:
1) Have the View itself have <SimpleLoader /> be displayed while any child item is rendering
2) identify when all the children have finished rendering (or the image, in particular), and then fade the view in.
I was reading around on potentially using a callback with componentDidMount but I'm not entirely sure how to achieve this.
An easy way would be to use react-native-image-progress
One way to do it manually would be to have a loaded: false property in the state initially, then set the onLoad prop of Image to a function that calls setState({loaded: true}). Then create a function, say showImage() that returns a view of either the image, or the loading indicator depending on whether state.loaded is true or false respectively. In render(), you can then call {this.showImage()}
To fade the image, you can use Animated to animate the opacity of the image inside the style from 0 to 1.

Categories

Resources