How can I detect when the user gets a View and do something after getting this position on React Native? - react-native

I have a ScrollView with some Views inside it, but I want to start an animation when the user gets to specific View and after it starts my animation.
Example:
<ScrollView style={{ width: DeviceWidth, height: DeviceWidth * 0.5 }}>
{/* When user position scroll is here,
is where I want to start the animation,
not since the page is loaded */}
<View style={{
width: DeviceWidth * 0.4,
height: DeviceWidth * 0.4,
resizeMode: "contain",
}}>
<ProgressBarAnimated
width={barWidth}
value={65}
backgroundColor="#F68D29"
height={40}
barAnimationDuration={6000}
/>
</View>
</ScrollView>

Instead of using a ScrollView you can instead use a FlatList, this gives you a lot more support for the type of indexing you're trying to do.
To detect when a user reaches a specific point you can use onViewableItemsChanged and the define which viewable items need to be on screen in order to trigger your animation.
FlatLists also support a number of build in animations like scrollToEnd or ScrollToIndex which may be helpful.

Related

Position absolute children on flatlist element in React Native (expo)

I want to make a little game when some circles comes from the top of the screen. After they appear they will drag down until they go out of the screen.
To make that i have a flatlist which contains all of the circles
<FlatList scrollEnabled={false}renderItem={this.renderItem}data={this.state.elements} />
Then in the render item I insert the circle item view
renderItem = ({item}) => (
<Circle
apparitionTime={new Date().getTime() / 1000}
id={item.id}
removeCircle={this.removeCircle}
updateScore={this.updateScore}/>
);
A circle item looks like this :
<Animated.View style={[/*this.moveAnimation.getLayout(),*/ styles.animatedView]}>
<TouchableOpacity style={styles.circleStyle} onPress={() => this.prepareToSend()}>
<View style={styles.absoluteView}>
</View>
<Image style={styles.image} source={require('../assets/images/music.png')}/>
</TouchableOpacity>
</Animated.View>
I use the animated view to make them scrolling all over the view.
I want the animated view to be on position absolute,but no matter what i've tried after sending the animated view to position absolute, the element disappear
animatedView: {
top: 0,
zIndex: 100,
width: 75,
height: 75,
position: "absolute", // does not work
},
Any Ideas ? Thank you
Position absolute didn't work inside a flatlist.
Now how to render positional elements inside it !!!!!!!....
Alternatively, you can use alignSelf: 'flex-end' or alignSelf:
'flex-start' and further you can place it by using margin/padding
inside the view. More you can read here about absolute not working in
their official docs

width: '100%' vs Dimension.get('window').width in react native

I'm new to react native and css styling as a whole so sorry if the question is very basic. I want a view to take 100% of the available screen width and when i use the code below my view seems to go outside the screen boundry, though when I use Dimension.get('window').width it work just fine. can someone explain how they differ from each other. any help would be really appreciated. thanks
return(
<TouchableOpacity style = {styles.food_wrapper}
onPress = {()=> this.userAction()}
>
<Text style = {styles.foodname}>
{this.name}
</Text>
<Text style = {styles.foodprice}>
Rs: {this.price}
</Text>
</TouchableOpacity>
);
food_wrapper:{
flex: 1,
flexDirection :'row',
justifyContent:'space-between',
alignItems:'flex-start',
width: '100%',//Dimensions.get('window').width,
minHeight: 50,
marginVertical: '1%',
padding: '2%',
backgroundColor: 'rgb(155,200,200)'
},
You need to understand what is the basic difference from 100% and the width you get using dimension.get('window')
100% means you want to get the container 100% width which mean if your parent container is 50px then 100% will return 50px.
the width from dimension give you a static width of your device width
so be careful to choose what to use to your component
if you want to follow the parent container then it is easier to use 100% then width from dimension but for responsive reasons without any parent container or it is the parent itself then width from dimension will work better
You need to add a wrapper view with flexDirection: 'row', then style the child view (or Touchable or whatever) with flex: 1
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1, height: 100, backgroundColor: 'grey' }} />
</View>
Or you could use alignSelf: 'stretch' inside a few with flexDirection: 'column' (which is the default for all views)
Hang in there. Learning flexbox takes some practice. Your first thought when you get stuck should be "do I need to add a wrapper view?"

Clickable Background underneath a ScrollView [React Native]

So, I want to create a layout similar to whats below. [Refer the Image]
So the background has a full screen MapView (React Native Maps) with Markers over it, which needs to be clickable.
And there is a Scrollview with full screen height over the MapView which initially has some top-margin associated with its contents.
But the issue if I arrange my Views this way, the Markers on the map are not clickable in the initial state.
<View>
<MapView>
<Marker clickEventHere></Marker>
<Marker clickEventHere></Marker>
</MapView>
<ScrollView fullscreen>
<View marginTop></View>
</ScrollView>
<View>
I am unsure if its really possible to solve this out.
Initial State
After Scrolling
Solution Tried
yScrolled = event.nativeEvent.contentOffset.y;
yValue = this.state.yValue - yScrolled;
upwardScroll = yScrolled > 0;
if(upwardScroll && (yValue > 0)){
this.setState({
yValue: yValue
});
}
if(yScrolled === 0){
yScrolled = -10;
}
if(!upwardScroll && (yValue <= scrollViewMarginTop)){
yValue = this.state.yValue - yScrolled;
console.debug("UPDATE DOWNWARD");
this.setState({
yValue: yValue
});
}
I'd start with adding absolute positioning to your ScrollView, (position: absolute) starting at whatever y coordinate you would like. I would make this y value a state, eg
yValue: new Animated.Value(start_value) or simply yValue: start_value
I would then use ScrollView's prop onScroll event to handle the change in this y coordinate, for example for the first 100 pixels of a scroll it would simply change the yValue instead of scrolling the view.
This should enable you to press the markers you have in your parent view, and use the same component structure that you have provided.
Note: You would need to do this for collapsing the scrollview also.
Note2: if this doesn't give you the result you were looking for, i'd suggest looking into using some sort of collapsable component for this task, eg https://github.com/oblador/react-native-collapsible
Hope this helps
EDIT: To collapse the scrollview you could first identify if the scroll direction is downwards ( which i think youve done via upwardScroll ) and then..
1) Either simply add the content offset to your yValue
2) If you used Animated.Value for yValue, you can have an animate function that animates the scrollview downwards to your desired position. I think this would look nicer as the user would only need a simple downwards flick to collapse the view, which seems like the industry standard.
There is also a library that is called react-native-touch-through-view that can do this for you. This it how it works basically:
<View style={{ flex: 1 }}>
// Your map goes here
</View>
<TouchThroughWrapper style={{
position: 'absolute'',
top: 0,
left: 0,
width: '100%',
height: '100%',
}}>
<ScrollView
style={{
backgroundColor: 'transparent',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
// Maybe in your case is flex: 1 enough
}}
bounces={false}
showsVerticalScrollIndicator={false}
>
<TouchThroughView
style={{
height: 400, // This is the "initial space" to the top
}}
/>
// The "slide up stuff" goes here
</ScrollView>
</TouchThroughWrapper>
For example, this then can look like this:
So the map is overlayed by the TouchThroughView that passes all the events right to the view behind. In my case this worked better than using pointer-events box-none.

How to show hidden view with translateX in React Native

Here is the code:
<View
style={{transform: [{translateX: this.state.translateX}], width: '120%'}}>
<View style={{width: '20%'}}>{someText}</View>
<View style={{width: '80%'}}>{someText}</View>
<View style={{width: '20%'}}>{someText}</View>
</View>
this.state.translateX was respond to swipe gesture which worked fine, the first two View did move but the last View was not visible (or not moved?). I want to show the last View when this.state.translateX changed. But it seems not being properly rendered?
It is because Android does not render element which is off screen. Solution is place the element in screen with position: 'absolute' and then use translateX to hide it from screen.

Add content in bounce margin of ScrollView in React Native?

In my app I'm using <ScrollView /> to view pages of a book scrolling horizontally. When a user gets to the end of the <ScrollView /> there is a bounce that shows a white area to the right that is only visible if the user drags the last page to the left. I want to add some text there that says "The End" vertically. How can I add content to the right of the <ScrollView /> in the bounce area?
I ALMOST figured it out. This is close but shows up in the right side of the last page but not off the page on the right in the bounce area. I want it to show up "to the right of the page" not "on the right side of the page." Any other ideas?
Create a <View style={styles.end} /> with this style:
theEnd: {
position: 'absolute',
top: 0,
right: 0,
width: 100,
height: 768, // Device height
alignItems: 'center',
}
Place it right before the <ScrollView /> and put whatever you want to show inside of the View component with the "theEnd" style.
This probably doesn't apply to your content, but I had the same situation except with a large image for the ScrollView content. I wanted both horizontal and vertical scrolling, where the edge of the image would show up only in the bounce margin. I figured out that the scale transformation works great for this:
<ScrollView horizontal={true}>
<Image
source={require('./img/map.jpg')}
style={{transform: [{scale: 1.1}]}}
/>
</ScrollView>
So the image takes up 110% of the height and width of its box (which is then inside a yet smaller ScrollView).
EDIT: FYI, after testing, discovered this only works on iOS, not Android. (Android won't allow vertical scrolling if you set horizontal to true, and also I think it didn't render the parts outside of the normal viewing area, so the bounce margin was empty.)
there is a prop for this called contentContainerStyle
<ScrollView
horizontal={true}
contentContainerStyle={{
paddingLeft: 25,
paddingRight: 25,
}}>
*** CONTENT ***
</ScrollView>