I have 3 ListView components inside a single ScrollView component like this:
<ScrollView>
<Header />
<ListView onEndReached={() => alert('load more 1')}/>
<ListView onEndReached={() => alert('load more 2')}/>
<ListView onEndReached={() => alert('load more 3')}/>
<Footer />
</ScrollView>
The Header component has some common content and also has 3 tabs, which trigger showing the respective ListView
The issue is any ListView with onEndReached={() => alert('load more 1')} never runs the alert, so I can never load more as I scroll down and hit the end of the listview. Remove the wrapping ScrollView and the alert runs, but the common Header doesn't scroll, since we just removed the wrapping ScrollView. The header needs to scroll with the listview, which is why I wrapped everything that needs to scroll in the ScrollView.
IMPORTANT NOTE:
I can't really use ListView with renderHeader={this.header}, for this scenario. Because, even though the Header will scroll, it will rerender the common Header and the 3 tabs for each ListView each time a ListView renders, instead of once. So a new Header rerender each time for each ListView won't cut it for the app.
Looking for a solution to this problem, where the Header scrolls with the listviews and the onEndReached is triggered for the visible ListView.
I think you're going to have to solve this by changing the dataSource in each listView in response to what header element is selected instead of loading three different ListViews.
getInitialState() {
return {
currentList: this.ds.cloneWithRowsAndSections(INITIAL_DATA);
}
},
render() {
return <ListView renderHeader={this._renderHeader} dataSource={this.state.currentList}/>
}
The only reason you wouldn't want to do this is if you wanted to maintain the scroll position in the three sub ListViews, but that wouldn't be useful because you always have to scroll to the top to change which ListView you're looking at anyway.
Then in your _renderHeader function you would render a selector that populates currentList with different data depending on the header selected.
In styling you can set it's position as relative with top:0 and left:0 . This way it will remain static on top.
<View>
<Header style={{position:"relative",top:0,left:0,height:30,width:Dimensions.get("window").width}} />
<ListView />
<ListView />
<ListView />
<Footer />
</View>
Second option which may work in scrollview is to specify height for all three ListView.
You can maybe use ScrollView::onScroll but it will be a little hacky. You will need to know the size of your listviews.
Work with ListView only
Maybe the best solution will be to play with the ListView dataSource and the onEndReached function.
If you update you dataset when ListView::onEndReached is triggered, I think you can add more elements to your ListView. This way, you do not need to do hacky things with ListViews in ScrollViews.
Related
Focussing of textinput of last item in flatlist appears keyboard but immeadiately keyboard disappears. In order to solve this,using a property removeClippedSubviews={false} of flatlist fixes this issue but it causes to another issue i.e,
Whenever an item is focussed aleardy in flatlist and tries to scrolling up the items, items are scrolling upto pagination limit and then right after items are scrolling down to the item that is focussed already of flatlist(focussed item appears on top of flatlist interms of visibility).Since it is not allowing scrolling up further.
Is there any property or workaround to fix these two issues? Do anyone got this issue? please provide solution if there is any?
Flatlist without "removeClippedSubviews={false}" property, scrolling is fine but for focussing of textinput of last item of flatlist causes keyboard appears and disappears.(keyboard should not disappear)
2.Using SafeAreaView, keeping flatlist in scrollview are also not working.
<FlatList style={styles.flatListSection}
keyExtractor={(item, index) => index.toString()}
data={this.state.serverData}
renderItem={this.iterateFlatListItem}
ItemSeparatorComponent={ () => this.seperatorComponent() }
ListFooterComponent={this.renderFooter.bind(this)}
onEndReachedThreshold={0.5}
onEndReached={()=>this.handleLoadMore()}
keyboardShouldPersistTaps='always'
extraData={this.props}
ref={ (r) => this.refFlatlist=r }/>
Scrolling up should work without scroll down automatically when textinput is focussed
Focus of text input of last item of flatlist, keyboard should not diappear once it appears unleass we dismiss it manually
I have a view that has top banner and some text, and after that there is a list of product which uses pagination, what I want to do is use flat list, Is there a way to configure it so that in my renderItems I'll return my products and have the the static content in same flat list?
If your Banner and text will always be on top of product list then you can use ListHeaderComponent prop of Flatlist to render static content(e.g. banner and text).
<FlatList
...
ListHeaderComponent={this.renderHeader}
/>
If you have fixed banner and some text before the flatlist. You can wrap the banner, text and flatlist in scrollView.This will work as you wanted.
render(){
return(
<ScrollView>
this.renderBanner();
this.renderText();
this.renderFlatList();
</ScrollView)
}
I click on a button on one screen which loads another screen with a flat list which renders many rows. My conundrum is that I hang on the first screen while the flatlist processes.
My best effort so far is a loader, hidden this.props.children to process the flatlist, then hide the loader and show this.props.children again.
I'm sure there must be a more logical approach?
Ta,
Chris
first instead ho hiding flatlist and showing loader you can use
Refresh Control from React-native. which will we do the same same job
with ease.
second if your list is long you can lazy load your data by using onEndReached Callback this will decrease the loading time .
third make your renderComponent in flatlist a pure Component .which will stop unecessary refreshes and increase performance.
check the code below .....
<FlatList
data={this.props.questions}
renderItem={({ item, index }) => <QuestionCard //your pure component
item={item}
index={index}
onPress={this.openQuestionDetail}
/>
}
ref={'flatlist'}
refreshControl={
<RefreshControl //imported from react-native
refreshing={isFetching} //used to show loader while loading
onRefresh={this.fetchQuestions}
title="Pull to refresh"
tintColor="#fff"
titleColor="#fff"
colors={[Colors.secondary_button]}
/>
}
onEndReached={this.handleDynamicLoading} //callback for lazyloading
onEndReachedThreshold={0.5}
keyExtractor={(item, index) => item.qid}
/>
hope this helps... :)
Im trying to implement a screen transition effect, when a user clicks on a Box Component (inside a ScrollView), the image will scale and move to the top, Airbnb has a great example of this:
Airbnb scale transition
<ScrollView>
<Box /> // onPress the scaleImage comp should move to top screen
<Box /> // regardless of scroll position
<Box />
<Box />
...
</ScrollView>
<Animated.Image
style={styles.scaleImage}
source={this.state.activeImage} />
I know how to implement the animation part of this, but the problem Im having is the layout, if the images that Im trying to scale and move to the top are in a ScrollView, how can I determine the distance to get to the top.
You could try using React Native's measure function. You can give it any native component (View, ListView, Image, etc.) and it will give you that component's offsets to its frame (the native view which contains it), its page (the screen borders), and its width/height in a callback as soon as rendering is done (or immediately, if rendering is already done)
To get a reference to your image component, define it as:
<Image ref="myImage" /*...*/ />
Then, within your component class, you can do:
this.refs.myImage.measure((frameX, frameY ,width, height, pageX, pageY) => {
//do stuff with the measurements
})
In your case, you would likely want to use pageX and pageY as they will give you the absolute position of your image. Just remember this function only works on native components and not on user-defined components, so you should call it on the actual Image component and not on any wrappers you define around it.
I want to animate an element in a ListItem
For example, consider the following simple ListView:
<ListView>
<Templates>
<ItemTemplate name="foo">
<View layout="vertical">
<Label color="red" id="label" bindId="bExampleLabel"/>
<Button onClick="onClickButton">Click Me to make the label go blue</Button>
</View>
</ItemTemplate>
</Templates>
<ListSection id="exampleListSection">
<ListItem template="foo" bExampleLabel:text="Example 1"></ListItem>
<ListItem template="foo" bExampleLabel:text="Example 2"></ListItem>
</ListSection
</ListView>
and the following script:
function onClickButton(e) {
var item = $.exampleListSection.getItemAt(e.itemIndex);
item.bExampleLabel = {
color: 'blue'
};
$.exampleListSection.updateItemAt(e.itemIndex, item);
}
The above XML code simply has a ListView which contains 2 ListItem, which each contains a label and a button. When you click the button, it makes the label go blue.
However I want it so that it animates it to blue.
Usually this is done like so:
$.elementId.animate({
color: 'blue'
});
However, I do not know how to do this in the context of a ListItem as you cannot seem to access the objects directly.
you can't animate ListItem in listView, you can change only the item properties accessing with bindId
templates : Dictionary
Contain key-value pairs mapping a style name (key) to an ItemTemplate (value).
This property cannot be changed once a window has been opened.
if you want to set animation in listing use TableView, and you can do what you want with TableViewRow