I have a horizontal scroll view and inside of it I've some views:
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}>
{myData.map((dataObj, index) =>
<MyTestCell />
)}
</ScrollView>
The MyTestCell is a custom component and everything in it inside a <View></View>
Based on the content some MyTestCell are larger in height than others. Is there a way to NOT let MyTestCell View take the height of the longest component?
For example here is a screenshot of the bottom part of a cell which is just there because another cell in the scroll view is of that height:
So, is there a fix to this? Basically, I'm asking if there is a way to absolute the height of a view inside scroll view rather than inheriting the height of its parent it should just keep the height which it requires.
It might be late but you can do it but setting the flexGrow to 0 on the child component.
Related
In a react-native project, there is a parent flatlist/scrollview. inside each item in this parent list, there exists a nested scroll view.
Expected behavior: When the parent scroll view is locked, the parent should NEVER scroll, only the child scrollview should be allowed to scroll. and when the outer bound of the child scroll view is met (meaning youve scrolled to the bottom or all the way back to the top of child view), the parent remains locked
What actually happens: with parent view scroll-locked, scrolling the child scrollview to the very bottom/top will scroll the parent scroll view, once the child scroll view reaches its scroll-boundary
Steps to reproduce behavior:
flick one of the child scroll views downward until it reaches the bottom
(even though youve reached the downward boundary) attempt to scroll the child down even more
observe the fact the parent scroll view now scrolls instead, even though the parent scroll view is locked
How can the parent scroll view be truly prevented from scrolling when nested-scroll-view reaches the end of its view?
only noticed this on android, but could possibly exist on ios as well.
here is a minimum reproducible example: https://staging.snack.expo.dev/b3XuJ6iA3
You are nesting multiple ScrollViews inside a FlatList, which is a convenience wrapper around ScrollView (compare with the documentation) , but you are setting nestedScrolEnabled to true in the child ScrollViews. You need to set it on the parent ScrollView (the FlatList).
The following code completely disables scrolling for the parent FlatList while allowing scrolling in all nested ScrollViews.
const _renderItem = ({item, index}) => {
return (
<View style={{height: 300, borderColor: 'blue', borderWidth: 1, marginBottom: 20}}>
<Text> Non scroll View area </Text>
<ScrollView contentContainerStyle={{height: 500, borderColor: 'red', borderWidth: 3}}></ScrollView>
</View>
)
}
return (
<View style={styles.container}>
<FlatList data={data} renderItem={_renderItem} scrollEnabled={false} nestedScrollEnabled={true}/>
</View>
);
}
Here is a working snack of your code with the changes mentioned above which I have successfully tested on Android (Samsung Galaxy S9) and iOS (iPhone 12).
New to react native. Here is what I am trying to do:
Render a page with three components: top panel, middle row, and content box.
When the user scrolls down, the top panel is scrolled and disappears, middle row is scrolled but is sticky to the top of the screen, and the content box is scrolled all the way down until the end of the content.
Below code serves my intention. However, when I use this code, I get warnings about nesting virtualized views.
return (
<View style={style.profileContainer}>
<ScrollView
stickyHeaderIndices={[1]}
showsVerticalScrollIndicator={false}
>
<TopPanel /> // This is a view component and is scrolled up as the user scrolls down.
<MiddleRow /> // This is a view component that is sticky to the top of the screen
<BottomArray /> //This is a FlatList
</ScrollView>
</View>
)
Below code gets rid of the warning but all the scroll/sticky behaviors of the top/middle components disappear. They just remain fixed as the user scrolls down.
return (
<View style={style.profileContainer}>
<SafeAreaView style={{flex:1}}>
<TopPanel /> // This is a view component and is fixed as the user scrolls down.
<MiddleRow /> // This is a view component and is fixed as the user scrolls down.
<BottomArray /> //This is a FlatList
</SafeAreaView>
</View>
)
Is there a way to make the top panel scrollable and middle row sticky without relying on ScrollView? This is one of the key interfaces of the app and I'd like to keep it alive.
Thanks!
I think if you put the Middle Row inside a Scroll View, that will help. I am new to react-native, so I am pretty sure this won't help you a lot and I think you would have already tried it.
If i understand correctly what you are looking to achieve, you can wrap the 3 boxes inside a view, have the top and middle inside a view and the content inside a scrollview:
<View>
<View><Text>TOP SECTION</Text></View>
<View><Text>Sticky section</Text></View>
<ScrollView><Text>...Content</Text></ScrollView>
</View>
then using animate you can animate the size (for the top section) and the position (of the sticky section) based on the scroll position of the content section.
first you define you scrollY as a ref:
const scrollY= useRef(new Animated.Value(0)).current;
then you convert the views to Animated and "link" the scrollY ref to the scrolling of the scrollview:
<View>
<Animated.View><Text>TOP SECTION</Text></Animated.View>
<Animated.View><Text>Sticky section</Text></Animated.View>
<Animated.ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }], // attach the scroll to scrollY
{ useNativeDriver: true },
)}>
>
<Text>...Content</Text>
</Animated.ScrollView>
</View>
at this point you can define the function that handle position, size, opacity and so on based on the scrollY position, assuming you know the header height, this function interpolate (map the values) the scroll position of the scrollview from 0 to the height of the header, giving an innverse output range (from 0 to -header heigth):
const headerTranslateY = scrollY.interpolate({
inputRange: [0, HEADER_HEIGHT],
outputRange: [0, -HEADER_HEIGHT],
extrapolate: 'clamp',
});
this function can be attached to the trasform property of the style of the view that you want to animate:
<Animated.View styles={[styles.customstyle, {transform: [{ translateY: headerTranslateY }]}]><Text>TOP SECTION</Text></Animated.View>
basically with interpolate you constatly set values of something, based (in this case) of the scrolling offset of your scrollview (you can read more here on interpolation https://reactnative.dev/docs/animations#interpolation)
I'm new to React-native and I've a very simple(at least i think so) problem.
I've an ImageBackground with resizeMode='contain', now I would like to have the background positioned to the top of the container...
<ImageBackground style={styles.imageBackground} source={backgroundImage} resizeMode='contain'>
... some content
</ImageBackground>
The image is rendered in the right way, but the problem is that it is vertically centered, instead I would like to have it top aligned...
This is an example of the result of my ImageBackground
This is an example of the result with the bottom added to ImageStyle
In the ImageBackground component, the image isn't vertically centered, rather it is positioned absolutely to fill the container. You can check the source here. The reason it's appearing vertically centered is probably because of the resizeMode contain. To top align it, you can make user of the prop imageStyle that you can set to something like this:
<ImageBackground
imageStyle={{
bottom: 40 // Whatever offset you want from the bottom
}}
/>
I have created a FlatList like this:
<View style={{flex:1}}>
<FlatList
data={rows}
renderItem={renderRow}
/>
</View>
It is extremely simple. However on screen load, the flat list height is not full height. It renders at like 70% the actual height. Then after a second it goes to proper height of filling the remainder of the screen.
I want to avoid this "flash" adjustment, and instead, it should initially render with the height it "flash" updates to.
I uploaded a screencast here - https://www.youtube.com/watch?v=hO_cF6dCrEU
I am showing pictures gallery in full screen mode. I am using scrollview in horizontal for scrolling the pictures. Right now I can scroll the pictures by swiping left or right and I using the pagingEnabled enabled props.
But I want to add more gesture, where when user tap on left or right ( a distance from the edge) , it will automatically mapping the swapping gesture. How can I do this?
I assume your scroll view looks like this with pagingEnabled and horizontal props.
<ScrollView
horizontal={true}
pagingEnabled={true}
onMomentumScrollEnd={event => {
this.setState({xOffset: event.nativeEvent.contentOffset.x })
}}>
// Content
</ScrollView>
The position can be calculated with :
this.state.xOffset/ DeviceSize.width
onMomentumScrollEnd is called each time you scroll an item in the ScrollView
(the content must be full width in this case)
Get a ref to the <ScrollView> then to scrollToEnd() or use scrollTo methods - https://facebook.github.io/react-native/docs/scrollview.html#scrollto
To calculate page number, you would use onLayout to calculate sizes of your pages. If it's the width of the device then that's easy, just use Dimensions.get('window').width then feed that to the x in scrollTo.