How i can animate a single item from flatlist ?
I tryed adding a value to isolate the selected record but didnt' work,maybe i wrote something wrong. Atm the animation is on ALL records
Flatlist:
<View style={style.container}>
<FlatList
data={this.state.ReturnedArray}
width='100%'
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={this.renderizza}>
Render Flalist :
renderizza = (item) => {
var str = JSON.parse(JSON.stringify(item.item.itemType)).name + ' ' + JSON.parse(JSON.stringify(item.item.itemType)).cognome
let acronym = str.split(/\s/).reduce((response, word) => response += word.slice(0, 1), '')
return (
<View style={style.containerFlat}>
<View style={style.containerFlat1}>
<Text style={style.txt}>{JSON.parse(JSON.stringify(item.item.itemType)).name} {JSON.parse(JSON.stringify(item.item.itemType)).cognome}</Text>
</View>
<TouchableOpacity style={style.containerFlat2} onPress={() => this.badge(JSON.parse(JSON.stringify(item.item.itemType)).expoToken)}>
<Animated.View style={[style.animatedView, { opacity: this.state.fadeValue}]}><Text>ADDED</Text></Animated.View>
<Text style={style.AvatarTxt} >{acronym}</Text>
</TouchableOpacity>
</View>
)
}
And here the animation :
badge(chiavi) {
console.log(chiavi)
if ((this.state.SelectedUser).includes(chiavi)) {
this.state.SelectedUser.splice(this.state.SelectedUser.indexOf(chiavi), 1)
Animated.timing(this.state.fadeValue, {
toValue: 0,
duration: 0
}).start();
} else {
this.state.SelectedUser.push(chiavi)
Animated.timing(this.state.fadeValue, {
toValue: 1,
duration: 0
}).start()
}
}
Hot to fix ?
Thank you
One way is to maintain an active item in the state and use extraData prop for this variable in Flatlist.Then conditionally render between the Animated and normal Item.
animate = index => {
this.setState({
activeItem: index,
});
//Rest of animation code.
};
<TouchableOpacity onPress={e => this.animate(index)}>
{this.state.activeItem === index && (
<Animated.View
style={[
styles.button,
{ transform: [{ scale: this.animationMap }] },
]}
>
<Text>{item.title}</Text>
</Animated.View>
)
}
{this.state.activeItem !== index && (
<View style={styles.button}>
<Text>{item.title}</Text>
</View>
)
}
</TouchableOpacity>
Here is an sample Demo
Related
I am using the react-native-flatlist to scroll the largest data from the server and fetching and displayed on my screen. But here i am facing two issues.
Scroll is not smooth
While scrolling the largest data it shows white space.
This is my sample code.
componentDidMount() {
let { page } = this.state;
this.props.fetchAllItems();
if (page == 0) {
page = page + 1;
this.setState({page: page})
this.props.fetchItemsPerPage(page);
}
}
renderList(){
return(
<TouchableOpacity activeOpacity = { .5 } >
<View style={{backgroundColor: 'white', alignItems: 'center'}}>
<FastImage style={{width: deviceWidth, height: deviceWidth}} source={item.uri}/>
</View>
</TouchableOpacity>
);
}
_renderFooter(){ return <ActivityIndicator color="#000000" style = {{marginBottom:10, marginTop:10}}/>; }
shouldItemUpdate(){
return false;
}
renderListItems(){
return(
<FlatList
ref={(ref) => { this.flatListRef = ref; }}
data={Items}
renderItem={({ item }) => this.renderList(item)}
numColumns={2}
extraData={this.props.pagination}
keyExtractor={item => item.id}
onEndReached={this._handleMoreItems}
maxToRenderPerBatch={10}
initialNumToRender = {14}
shouldComponentUpdate= {this.shouldItemUpdate()}
onEndReachedThreshold={0.001}
ListFooterComponent={this._renderFooter}
legacyImplementation = {true}
bounces = {false}
onMomentumScrollEnd={e => this.scroll(e.nativeEvent.contentOffset)}/>
)
}
render(){
return(
{this.renderListItems()}
)
}
Try using something like this (for performance):
getItemLayout={(data, index) => (
{length: 80, offset: 80 * index, index}
)}
I'm trying to add a badge on a View ,by a TouchableOpacity on press.
The trouble is the animation work appears only on one element at a time and not on two or more simultaneously
Here the code :
Flatlist :
<FlatList
data={this.state.ReturnedArray}
width='100%'
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={(item, index) => 'key' + index}
renderItem={this.renderizza}
extraData={this.state.activeItem}
/>
Render funtion :
<View style={style.containerFlat}>
<View style={style.containerFlat1}>
<Text style={style.txt}>{item.name} {item.cognome}</Text>
</View>
<TouchableOpacity style={style.containerFlat2} onPress={() => this.badge(item.expoToken,index)}>
{(this.state.activeItem === index) ? <Animated.View style={[style.animatedView, { opacity: this.state.fadeValue }]}><Text>ADDED</Text></Animated.View> : null}
<Text style={style.AvatarTxt} >{acronym}</Text>
</TouchableOpacity>
</View>
Badge function add Token into an array and lunch animation :
badge(chiavi, index) {
if ((this.state.SelectedUser).includes(chiavi)) {
this.Nonanimate(index)
this.state.SelectedUser.splice(this.state.SelectedUser.indexOf(chiavi), 1)
} else {
this.state.SelectedUser.push(chiavi)
this.animate(index)
}
}
and the animation / NotAnimation :
animate = (index) => {
this.setState({
activeItem: index,
});
Animated.timing(this.state.fadeValue, {
toValue: 1,
duration: 0
}).start()
};
Nonanimate = index => {
this.setState({
activeItem: index,
});
Animated.timing(this.state.fadeValue, {
toValue: 0,
duration: 0
}).start()
};
i'm wasting days on this trouble. Suggest ?
Here the function to solve this :
badge = chiavi => {
//console.log(chiavi.item.expoToken)
if ((this.state.SelectedUser).includes(chiavi.item.expoToken)) {
// this.Nonanimate(index)
this.state.SelectedUser.splice(this.state.SelectedUser.indexOf(chiavi.item.expoToken), 1)
} else {
this.state.SelectedUser.push(chiavi.item.expoToken)
// this.animate(index)
}
chiavi.item.isSelect = !chiavi.item.isSelect;
chiavi.item.selectedClass = chiavi.item.isSelect ?
style.selected : style.containerFlat1;
const index = this.state.ReturnedArray.findIndex(
item => chiavi.item.user_id === item.user_id
);
this.state.ReturnedArray[index] = chiavi.item;
this.setState({
ReturnedArray: this.state.ReturnedArray,
});
and Flatlist :
<FlatList
data={this.state.ReturnedArray}
width='100%'
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={item => item.user_id.toString()}
renderItem={item => this.renderizza(item)}
extraData={this.state}
/>
Source : Link here
I have a FlatList and I want to implement a radio button.My idea is to change the selected property of an element in this.state.data to control it,but I am a newbie, I don't know how to change the property of an element in this.state.data.
Here is my code:
this.state = {
data: [
{
month:1,
price:18,
selected:true
},
{
month:3,
price:48,
selected:false
},
{
month:12,
price:128,
selected:false
},
],
};
<FlatList
data={this.state.data}
renderItem={({item, index, separators}) => (
<TouchableOpacity onPress={() => this.radio(index,item)}>
<View style={item.selected ? {borderWidth:3,borderColor:'#FFA371',borderRadius:15}:{}}>
<View style={styles.itemDefalut}>
<View style={{ flexDirection: "column", flex: 1 }}>
<Text>
Months
</Text>
<Text>{item.month} Months</Text>
</View>
<View>
<Text>${item.price}</Text>
</View>
</View>
</View>
</TouchableOpacity>
)}
/>
radio(index,item) {
for (var variable in this.state.data) {
variable.selected = false;
}
item.selected = true;
}
first pass only index from onpress
onPress={() => this.radio(index)
then in radio function do something like this
radio = index => {
let data = [ ...this.state.data ];
this.state.data.map((elem,key)=>{
if(elem.month==data[index].month){
data[key]={...data[key], selected: true};
}else{
data[key]={...data[key], selected: false};
}
})
this.setState({ data:data});
}
radio(item) {
let data = [...this.state.data];
let index = data.findIndex(el => el.month === item.month);
data[index] = {...data[index], selected: !item.selected};
this.setState({ data });
}
In TouchableOpacity on press it should be
<TouchableOpacity onPress = {this.radio.bind(this,item)}>
I want to start the offset of my list but move the initial viewPosition. The FlatList is currently showing the current image + next image on the list but rather would want to show the current image + previous one.
I'm already using initialScrollIndex and I can scrollToIndex of the image but I'm thinking that it might show some jank on first mount
Here is the image with initialScrollIndex exactly on the item I want.
The behavior I want is using initialScrollIndex and showing the previous item instead of the next.
export default class App extends Component {
flatList = null;
componentDidMount() {
setTimeout(() => {
this.flatList.scrollToIndex({
index: 3,
animated: false,
viewPosition: 1
})
}, 10)
}
setFlatList = (ref) => {
this.flatList = ref;
}
getItemLayout = (_, index) => ({
index,
length: 600,
offset: 600 * index
});
renderItem = ({ index }) => {
const backgroundColor =
index === 0 ? "blue" : index === 1 ? "red" : index === 2 ? "green" : index === 3 ? "yellow" : "white";
return (
<View style={{ height: 600, backgroundColor, width: 450, justifyContent: "center", alignItems: "center" }}>
<Text>{`item${index}`}</Text>
</View>
);
}
render() {
return (
<View style={styles.container}>
<View style={{ ...StyleSheet.absoluteFillObject }}>
<FlatList keyExtractor={(_, index) => `${index}`} getItemLayout={this.getItemLayout} ref={this.setFlatList} data={["yo", "1", "2", "3", "4"]} renderItem={this.renderItem} />
</View>
</View>
);
}
I am making a react-native app that has a custom view like a grid view. All the cells of the view have same size except one. I want to give condition for the cell to have double the size from others.
I am making the view through an array using map function. Map function is not taking if statement. How should I use it?
// Buttons Array
buttons = [['1', '2', '3'],
['a', 'b', 'c'],
['q', 'w', 'e'],
['+', '-', '*'],
]
// '-' has double size...
import React, { Component } from 'react';
import {
View,
Text,
TouchableNativeFeedback
} from 'react-native';
//Styles
import styles from './styles';
export default class NumberButtons extends Component {
//This will call the bound function from its parent component
//to handle button press action/event
_handleOnPress = (value) => {
requestAnimationFrame(() => {
this.props.onBtnPress(value);
});
}
render() {
return (
<View style={styles.container}>
{
this.props.buttons.map((row, index) => (
<View key={index} style={styles.contRow}>
{
row.map((col,index) => (
//**** Here I want to use if else for row and column ***//
<TouchableNativeFeedback
key={index}
onPress={() => this._handleOnPress(col)}
background={TouchableNativeFeedback.SelectableBackground()}>
<View style={styles.buttonContainer}>
<Text style={styles.text}>{col}</Text>
</View>
</TouchableNativeFeedback>
))
}
</View>
))
}
</View>
);
}
}
You can render conditional views like this
<View style={styles.container}>
{this.state.buttons.map((row, index) => {
const myRow = row
console.log("myRow",myRow)
return (
<View key={index} style={styles.contRow}>
{
row.map((col,index) => {
if(col != 3 && myRow != null ){
return (
<TouchableNativeFeedback
key={index}
onPress={() => this._handleOnPress(col)}
background={TouchableNativeFeedback.SelectableBackground()}>
<View style={styles.buttonContainer}>
<Text style={styles.text}>{col}</Text>
</View>
</TouchableNativeFeedback>
)
}
else {
return (
<TouchableNativeFeedback
key={index}
onPress={() => this._handleOnPress(col)}
background={TouchableNativeFeedback.SelectableBackground()}>
<View style={styles.buttonContainer}>
<Text style={{backgroundColor:'#78909C'}}>{col}</Text>
</View>
</TouchableNativeFeedback>
)
}
})
}
</View>
)})
}
</View>
Here is the sample code how you can insert if and else in the nested map function.
this.props.availableEvents.map((item, i) => {
if (i < this.state.imageIndex) {
return null
} else if (i === this.state.imageIndex) {
return (
<Animated.View
{...this.imagePanResponder.panHandlers}
key={i}
style={[this.rotateAndTranslate, styles.cardContainer]}
>
<View style={{ width: '100%', height: '100%' }}>
</View>
</Animated.View>
)
} else {
return (
<Animated.View
key={i}
style={styles.cardContainer}>
<View style={{ width: '100%', height: '100%' }}>
</View>
</Animated.View>
)
}
}).reverse();
};