How to get scrollview index - react-native

I am using react-native scrollview to slide my imageBackground.
I am using pagingEnabled to swipe the images. But is there a way I could get number of the index when ever I swipe?
I am using the scroll view like the code below. Adding pagingEnabled will make the scrollview work like a swiper but I don't know how to get the index.
<ScrollView horizontal={true} pagingEnabled={true}>
{this.createScrollImageSources(this.state.image)}
</ScrollView>

You could make use of the onScroll method together with the Dimensions module to calculate the currentScreenIndex.
Example:
render
<View style={styles.container}>
<ScrollView pagingEnabled horizontal style={{flex: 1}} onScroll={(e)=>this.handleOnScroll(e)} scrollEventThrottle={5}>
<View style={{width: SCREEN_WIDTH, backgroundColor: 'yellow'}} />
<View style={{width: SCREEN_WIDTH, backgroundColor: 'red'}} />
<View style={{width: SCREEN_WIDTH, backgroundColor: 'green'}} />
</ScrollView>
</View>
handleOnScroll
handleOnScroll(event){
//calculate screenIndex by contentOffset and screen width
console.log('currentScreenIndex', parseInt(event.nativeEvent.contentOffset.x/Dimensions.get('window').width));
}
Working Demo
https://snack.expo.io/HyxzFr2HxU

What I did was to use the onScroll prop to check the current offset of the horizontal scrollview. Then compare the current offset with your device width.
Try:
<ScrollView onScroll={this.handleScroll} />
And then:
handleScroll: function(event: Object) {
console.log(event.nativeEvent.contentOffset.x);
},

Related

Aligning ListHeaderComponent vertically above Horizontal Flatlist

I have a horizontal Flatlist and right above it i want to add a custom header. I have an option to wrap the Flatlist & custom header in a ScrollView - which isn't good practice according to RN 0.61
VirtualizedLists should never be nested inside plain ScrollViews with
the same orientation
Another option is to use:
ListHeaderComponent
<FlatList
horizontal
ListHeaderComponent = {<CustomHeader>What can we help you find?</CustomHeader> }
keyExtractor = {(item) => item.unique_id }
data = {this.props.categories}
contentContainerStyle={{ flexGrow: 1}}
renderItem={ ({item}) => (
<TouchableOpacity>
<View>
<Image
style={{
height:80,
width:100}}
source={{uri:'some_url'}}
/>
<Title>{item.category}</Title>
</View>
</TouchableOpacity>)}
/>
Whilst the above works with a vertical Flatlist, it completely fails with a horizontal flatlist with my use case.
Expected:
Actual Output:
What are the possible fixes?
You can Conditional Rendering like this, just a workaround
{this.props.category.length ? <CustomHeader>What can we help you find?</CustomHeader> : null}
<FlatList
horizontal
keyExtractor = {(item) => item.unique_id }
data = {this.props.categories}
contentContainerStyle={{ flexGrow: 1}}
renderItem={ ({item}) => (
<TouchableOpacity>
<View>
<Image
style={{
height:80,
width:100}}
source={{uri:'some_url'}}
/>
<Title>{item.category}</Title>
</View>
</TouchableOpacity>)}
/>

Horizontal scrolling in FlatList - React Native

I'm listing data with flatlist. But while listing the data, it lists it vertically, I want it to be sorted horizontally. So instead of scrolling down, I want to scroll left and right. I think it's called pagingEnabled. How can I do that?
<FlatList
style={{
flex: 1
}}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
data={this.state.allReasons}
keyExtractor={(item,index)=>index.toString()}
renderItem={({ item ,index}) => {
return (
<ScrollView onScroll={(event)=>{
this.setState({
activePage:Math.round(parseFloat(event.nativeEvent.contentOffset.x/Dimensions.get('window').width))
})
}}
style={{width:'100%'}} showsHorizontalScrollIndicator={false} pagingEnabled={true} horizontal={true}>
<View style={{width:'100%'}}>
<Image style={{ resizeMode: 'contain',width:Dimensions.get('window').width,height:250}} source={{uri:"http://ledslider.stechomeyazilim.com/" + item.Slider_Image}}/>
.....
</View>
Add horizontal prop in Flatlist like
horizontal={true}
Try removing scrollview from item may cause the issue

FlatList not filling 100% height in react-native

I got a FlatList that occupies the 50% of the vertical space on the screen.
This FlatList has only a few items, and because of this, is not taking the entire space but only the half of it, and when I scroll up/down, it looks as if it has overflow: hidden.
I read this in the RN GitHub about it, they recommended using flexGrow: 1 on the FlatList's contentContainerStyle, also the parent View with flex: 1. But is not working. Is this still working? They said to use it on ScrollViews, but isn't FlatList inherited from ScrollView or something like that?
This is my current structure:
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
numColumns={2}
style={ styles.cardContainer }
keyExtractor={ this._keyExtractor }
data={ this.state.listData }
renderItem={ this._renderItem }
>
</FlatList>
</View>
);
}
You actually want to put flex onto your FlatList. Currently you have it on your contentContainerStyle.
So flex:1 on your FlatList will make it fill the rest of the container.
You'll want to adapt this to your solution depending on what you currently have in styles.cardContainer.
<View style={{ flex: 1 }}>
<View style={{ height: Dimensions.get("window").height * 0.25 }} />
<FlatList
numColumns={2}
style={{ flex: 1 }}
keyExtractor={this._keyExtractor}
data={["1", "2", "3"]}
renderItem={this._renderItem}
/>
</View>
Set the contentContainerStyle of the FlatList to flexGrow: 1 will not block the scroll functionality on long list.
There might have issue with the old version, but latest works just fine.
https://github.com/facebook/react-native/issues/17944
To add onto this 2 years later, i had a justifyContent:center on my list container and that was what made the flex not fill the entire space. Otherwise flexGrow works.

React Native FlatList last item visibility issue

I am fetching products list and then displaying using a FlatList, my list contains 5 items and as you can see FlatList row height is variable because of varying description text. So the issue is my last item card is not completely visible maybe this is some kind of flat list issue or layout issue. Any help would be highly appreciated
renderProducts() {
if (this.props.loading === true) {
return (
<View style={Styles.spinnerStyle}>
<ActivityIndicator size='large' />
</View>
);
}
return (
<FlatList
data={this.props.myProducts}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<Card
title={item.title}
image={{
uri: item.image !== null ? item.image.src :'../resImage.jpg'
}}
>
<Text style={{ marginBottom: 10 }}>
{item.body_html}
</Text>
<Button
icon={{ name: 'code' }}
backgroundColor='#03A9F4'
fontFamily='Lato'
buttonStyle={{ borderRadius: 0, marginLeft: 0, marginRight: 0, marginBottom: 0 }}
title='VIEW NOW'
/>
</Card>
)}
/>
);
}
render() {
return (
<View>
<View style={Styles.viewStyle}>
<Text style {Styles.textStyle}>ProductsList</Text>
</View>
{
this.renderProducts()
}
</View>
);
}
Set bottom padding to the <FlatList> content container:
<FlatList
contentContainerStyle={{ paddingBottom: 20 }}
/>
Add {flex: 1} to the View tag housing the Flatlist component.
In my case,
const App = () => {
return (
<Provider store={createStore(reducers)}>
<View style={{ flex: 1 }}>
<Header headerText={'My App'} />
<ScreenTabs /> // this is my content with FlatList
</View>
</Provider>
);
};
export default App;
Just wrap it in a view with flex:1
<ParentView style={{flex:1}
<View style={{flex:1}}>
// Your flatlist
<View>
</ParentView>
Also, note that the each parent of this "View" in which Flatlist is wrapped must also be a View with Flex of 1. Otherwise, that your flatlist wont be visible.
use contentContainerStyle props of FlatList
<FlatList contentContainerStyle={{ paddingBottom: 20}} />
Latest update:
react-navigation has a SafeAreaView with an option to not show that bottom area.
import { SafeAreaView } from 'react-navigation';
<SafeAreaView forceInset={{ bottom: 'never' }} />
Old response below:
You can't see your list with flex: 1 because flex: 1 will grow the component to the parent. If the parent doesn't have flex: 1, it won't stretch to its parent or the screen. Keep in mind, however, that flex: 1 with a SafeAreaView will cause the bottom safe area to show. This will look bad if your SafeAreaView backgroundColor is a different color from your list's back ground.
My old workaround was to add an item to the bottom of the array of items, but I'm still exploring how to scroll past/under the bottom safe area margin with a FlatList (which is how I found this post to begin with).
Update: Using ListFooterComponent you can create even a plain white "footer" with height and/or a margin
For example (I wouldn't directly copy and paste this if I were you... there's surely a better way to detect bezel-less iPhones, especially in 2019 when we have more than one)
ListFooterComponent={<View style={{ height: 0, marginBottom: 90 }}></View>}
This is how I would do it, using the iPhoneX's height for now. But it's not future-proof since the conditional will need to be updated every time a new iPhone with no bezels comes out:
ListFooterComponent={<View style={{ height: 0, marginBottom: noBezels ? 90 : 0 }}></View>}
Or you could just always have some spacing at the bottom, like a loading gif, a message... whatever.
UPDATE 2:
I found out about react-native-device-info which has a hasNotch() method. I find that useful for styling for iPhones with no bezels by combining hasNotch() with Platform.OS === 'ios'
You can try this solution
For Vertical FlatList:
<FlatList
ListFooterComponent={<View />}
ListFooterComponentStyle={{height:200}}
/>
For Horizontal FlatList:
<FlatList
contentContainerStyle={{paddingRight:40}}
/>
For IOS issues you can apply some IOS specific props:
<FlatList
// ...
contentInset={{top: 0, bottom: 20, left: 0, right: 0}}
contentInsetAdjustmentBehavior="automatic"
// ...
/>
The solution with contentContainerStyle padding didn't seem the best overall for fixing the safe area IOS issues in my case.
Work very well for me
<FlatList
data={data}
contentContainerStyle={{ paddingBottom: 30 }}
style={{height: '95%'}}
renderItem={({ item, index }) => (
<ListItem item={item} onPress={() => handlePress(item, index)} />
)}
/>
Make use of the contentContainerStyle prop in the flatlist
<FlatList contentContainerStyle={{paddingBottom: 10}} />
For dynamic flatlist, you can assign height to the parent view. I resolved it with same.
<View style={{height:'80%'}}>
<Flatlist
extraData={data}
data={data}
renderItem={renderItem}
/>
</View>
I had the same issue and found the solution. To fix the issue just add style={{flex: 1}} for each View element who is a parent for FlatList.
See updated code below.
render() {
return (
<View style={{flex: 1}}> // Here you should add style as {flex: 1}
<View style={Styles.viewStyle}>
<Text style={Styles.textStyle}>ProductsList</Text>
</View>
{ this.renderProducts() }
</View>
);
}
This worked for me.
<View style={{flex: 1}}>
<FlatList
style={{flex: 1}}
data={data}
renderItem={({item}) => (
<ListItem item={item} onPress={() => handlePress(item)} />
)}
/>
</View>
#krish solution is great for the fixed-size list items, however as
#Neeraj Sewani said, it may not be suitable for dynamic size list items.
so you can fix the issue like this -in case direction is column -:
<View style={{height: '90%'}}>
<FlatList/>
</View>
Otherwise, -in case direction is row -:
<View style={{height: '90%', width:'90%'}}>
<FlatList/>
</View>
I was seeing this same problem in our Android + iOS React Native hybrid app. We embed the FlatList component within our native UIs inside a Fragment in Android and we were unable to scroll to the last item in the list, even though the scroll indicator would show that there was more to scroll, the ScrollView would simply not scroll further. I tried all the combinations of using a wrapping <View style={{flex:1}}> to wrap the FlatList as well as using contentContainerStyle={{flexGrow:1}} on the FlatList without success. Pursuing the clue further it turned out that the FlatList needs an absolute, predefined height on Android to allow scroll to the bottom - it works just fine on iOS but on Android using match_parent wasn't going to work. Since we need to support all types of devices, phone and tablet too, it wasn't possible to pre-define an absolute height either.
To fix this, I made a custom FrameLayout subclass to house the ReactRootView's fragment, which overrides onLayout() to ignore the child view measurements, forcing the views to have the exact dimensions of the FrameLayout, somewhat like so in Kotlin:
class StretchFrameLayout #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
for (child in children){
if (child.visibility == View.GONE) continue
child.updateLayoutParams {
this.width = measuredWidth
this.height = measuredHeight
}
if (needsRelayout){
handler.postDelayed({child.requestLayout()},1)
}
}
super.onLayout(changed, left, top, right, bottom)
}
}
This work very well in my case:
<FlatList
data={todos}
contentContainerStyle={{ height: '100%' }}
renderItem={({ item }) => <Todos items={item} pressed={pressed} />}
/>
I've solved it doing contentInset={{ bottom: data.length * itemStyle.height, }} with itemStyle.height being 50 worked fine.

ReactNative ScrollView will not scroll to the bottom

If I try to scroll to the bottom of my ScrollView, it bounces back to its default position and won't let me view the entirety of its content.
My ( truncated ) setup is fairly simple :
<View>
<View>
<ABunchOfStuff />
</View>
<View style={styles.sectionNode} >
<ABunchOfStuff />
</View>
<ScrollView> <------ My broken ScrollView :(
<View>
<ABunchOfStuff />
</View>
</ScrollView>
</View>
This is a simplified version of my actual code. But I'm reaching the conclusion that there's some kind of "unbounded height" going on as in this reference.
I did try making sure everything and all parents have flex: 1 all the way to the child <View> of my <ScrollView> and up to its parents. But that didn't seem to do the trick.
Any idea on how to debug this? I know ReactNative's website recommends this and says it would be easy to do in the inspector ( but with no instructions on how to do it ). If my assumption that there's an "unbounded height" issue, how would one go about and find this rascal unbounded node? Or is it something else?
Try taking flex out of the ScrollView entirely and just put flex: 1 on the parent. That did the trick for me.
For me the problem was setting a paddingVertical, paddingTop or paddingBottom on the ScrollView. Just don't do that. it influences the height of the content of the ScrollView, without the ScrollView adjusting to it appropriately.
The parent view must have style={{flex: 1}} then the scrollview can have style={{flex: 1}} 🥇
The bounded height thingy means the ScrollView itself must be bound.
If the ScrollView has unbounded height, it will stretch with your content and won't scroll.
You can just add height to the ScrollView and see how this works, from there on you can use absolute height or use flex in a way that will limit the ScrollView height to what you want.
This worked for me:
<View style={{flex: 1}}>
<ScrollView>
<View style={{paddingTop: 16, paddingBottom: 16}}>
<SearchBar />
<ItemsContainer />
</View>
</ScrollView>
</View>
You must make sure that ScrollView has fixed height, either by setting it for parents or for itself.
I use flex to set its height instead of specifying it directly so it works on all screen size. So for your code something like
<View style={{flex: 1}}>
<View>
<ABunchOfStuff />
</View>
<View style={styles.sectionNode} >
<ABunchOfStuff />
</View>
<ScrollView style={{flex:0.8}}>
<View>
<ABunchOfStuff />
</View>
</ScrollView>
</View>
More information in react native docs
This works for me
<ScrollView>
<View style={{height:2000}}>
</View>
<ScrollView>
The important thing is to put a defined height for the elements that are inside the ScrollView
<ScrollView style={{flex: 1, marginBottom: 30}} />
items
</ScrollView>
What worked for me was to wrap the ScrollView in View. Then giving the View a height and setting flex : 1 on ScrollView.
Something like this:
<View style={{ height: "60%" }}>
<ScrollView style={{ flex: 1 }}>
<List/>
</ScrollView>
</View>
The suggested answers above with parent flex: 1 and child flex: 1 work, but this thing was causing my bug.
I had <Image> with percentage height and once I replaced the percentage with a number, it fixed the issue.
this will solve your problem
<ScrollView
contentContainerStyle={{flexGrow:1,justifyContent:'space-
between'}}
>
<The Other Components or Lists/>
</ScrollView>
add <Text></Text>
at the bottom inside scrollview. it will give some space