how to Use if in FlatList - react-native

I have array which has images. I want to give show images in flatlist everything is ok now. But I want to show some of them I mean if condition is true show that image.
this is my code:
renderItem={ ({ item }) =>
{
if (true) {
<View style={{ width: '22%', marginLeft: '3%', marginTop: '2%', alignItems: 'center' }} >
<TouchableOpacity onPress={() => this.props.navigation.navigate('DescriptionPage', { data: item.call })}>
<ImageBackground source={item.img} style={{ width: 60, height: 60 }} />
</TouchableOpacity>
</View>
}
else {
...
}
}
}
if I use like this there is no error and it shows all images.
<FlatList
data={images}
keyExtractor={(item, index) => index.toString()}
numColumns={4}
renderItem={ ({ item }) =>
<View style={{ width: '22%', marginLeft: '3%', marginTop: '2%', alignItems: 'center' }} >
<TouchableOpacity onPress={() => this.props.navigation.navigate('DescriptionPage', { data: item.call })}>
<ImageBackground source={item.img} style={{ width: 60, height: 60 }} />
</TouchableOpacity>
</View>
}
/>
There is mistake here I dont know why :
{
if (true)
{
...
}
else
{
...
}
}

you forgot to add return inside if else condition:
do it like this:
renderItem={ ({ item }) =>
{
if (true) {
// add return
return(
<View style={{ width: '22%', marginLeft: '3%', marginTop: '2%', alignItems: 'center' }} >
<TouchableOpacity onPress={() => this.props.navigation.navigate('DescriptionPage', { data: item.call })}>
<ImageBackground source={item.img} style={{ width: 60, height: 60 }} />
</TouchableOpacity>
</View>
)
}
else {
// add return
return(
...
)
}
}
}

Just use this kind of setup:
return (isTrue) ?
<TouchableOpacity onPress={() => this.props.navigation.navigate('DescriptionPage', { data: item.call })}>
<ImageBackground source={item.img} style={{ width: 60, height: 60 }} />
</TouchableOpacity> : null;
This should render the component if it is true, else, it won't render anything.

Related

react-native-video inside flatlist showing black screen after scrolling some videos

I am developing a flatlist with full screen videos like tiktok, it works fine for first 16/17 videos then when I scroll further it shows black screen.
Following is my code for the flatlist:
<FlatList
style={{
width: width,
height: this.state.videoHeight,
}}
getItemLayout={(data, index) => ({
length: this.state.videoHeight,
offset: this.state.videoHeight * index,
index,
})}
onScrollToIndexFailed={(info) => {
const wait = new Promise((resolve) =>
setTimeout(resolve, 500),
);
wait.then(() => {
this.flatlistRef.current?.scrollToIndex({
index: info.index,
animated: false,
});
});
}}
showsVerticalScrollIndicator={false}
data={this.state.allVideos}
ref={this.flatlistRef}
scrollEnabled={!this.state.isMinimizePlayer}
viewabilityConfig={this.viewabilityConfig}
decelerationRate={0}
removeClippedSubviews={true}
snapToAlignment={'start'}
snapToInterval={this.state.videoHeight}
horizontal={false}
onViewableItemsChanged={this.onViewableItemsChanged}
renderItem={this.renderItem}
keyExtractor={(item, index) => item.id}
/>
Render function code
renderItem = ({item, index}) => (
<PlayerContext.Consumer>
{({setVideo, setMetaData}) => (
<TouchableOpacity
onPress={() => {
if (!this.state.isMinimizePlayer) {
this.setState({isPause: !this.state.isPause});
} else {
this.maximizePlayr();
}
}}
activeOpacity={0.9}
style={{
width: width,
height: this.state.videoHeight,
}}>
<Video
// hideShutterView={false}
// useTextureView={true}
ref={(ref) => {
this.playerRef[index] = ref;
}}
style={{
backgroundColor: 'black',
width: this.state.videoWidth,
height: this.state.videoHeight,
}}
resizeMode={'cover'}
muted={this.state.isMute}
paused={
index == this.state.currentVisibleIndex
? this.state.isPause
: true
// index !== this.state.currentVisibleIndex ||
// !this.state.isPause
}
onLoad={(data) => {
// console.log('===>' + index);
}}
controls={false}
hideShutterView={true}
repeat={this.state.isLoop}
onEnd={() => {
if (!this.state.isLoop) {
if (this.state.isAutoPlay) {
if (
this.state.currentVisibleIndex <
this.state.allVideos.length - 1
) {
if (this.state.setGoNext) {
this.setState({setGoNext: false});
this._goToNextPage();
setTimeout(() => {
this.setState({setGoNext: true});
}, 1000);
}
} else {
setVideo(null);
}
}
}
}}
onProgress={(progress) => {
if (this.state.currentTrackDuration == 0) {
this.setState({
currentTrackDuration: progress.seekableDuration,
});
}
this.setState({
progress: progress.currentTime / progress.seekableDuration,
});
}}
bufferConfig={{
minBufferMs: 15000,
maxBufferMs: 50000,
bufferForPlaybackMs: 1500,
bufferForPlaybackAfterRebufferMs: 1500,
}}
source={{uri: item.url}}
poster={item.url}
onError={(e) => console.log('video load failed!' + index, e)}
onVideoError={(e) =>
console.log('video error load failed!' + index, e)
}
onReadyForDisplay={() => {}}
posterResizeMode={'cover'}></Video>
{this.state.isMinimizePlayer && (
<View
style={{
backgroundColor: this.ThemedColors.happy,
position: 'absolute',
width: this.state.videoWidth,
justifyContent: 'center',
alignItems: 'center',
height: this.state.videoHeight,
}}>
<TouchableOpacity
onPress={() => {
this.setState({isPause: !this.state.isPause});
}}>
<IconM
name={!this.state.isPause ? 'play-arrow' : 'pause'}
size={28}
color={'white'}
/>
</TouchableOpacity>
</View>
)}
{this.state.isMinimizePlayer && (
<View
style={{
flexDirection: 'row',
flex: 1,
height: this.state.videoHeight,
justifyContent: 'space-between',
alignItems: 'center',
top: 0,
bottom: 0,
left: 110,
position: 'absolute',
right: 10,
}}>
<View
style={{
flex: 1,
paddingHorizontal: 10,
justifyContent: 'center',
}}>
<Text style={{}} numberOfLines={1}>
{item.name}
</Text>
<View
style={{
marginTop: 5,
flexDirection: 'row',
paddingLeft: 0,
alignItems: 'center',
}}>
<Image
source={require('../../../assets/Images/icon_eye.png')}
style={{
height: 10,
width: 16,
tintColor: 'black',
resizeMode: 'contain',
}}
/>
<Text style={{marginLeft: 2}}>{this.metaData.from}</Text>
</View>
</View>
<TouchableOpacity
onPress={() => {
setVideo(null);
}}
style={{
height: 50,
width: 50,
alignItems: 'center',
justifyContent: 'center',
}}>
<Icon name="close" size={20} color={'black'} />
</TouchableOpacity>
</View>
)}
{!this.state.isMinimizePlayer && (
<LinearGradient
colors={['#000000', '#80000000']}
style={{
position: 'absolute',
top: 0,
paddingTop: Platform.OS == 'ios' ? width * 0.1 : width * 0.04,
left: 0,
right: 0,
}}>
<Text style={this.ThemedStyles.videoTitleText} numberOfLines={1}>
{item.name}
</Text>
<View style={this.ThemedStyles.videoMomentContaine}>
<Text style={this.ThemedStyles.videoDateText}>
{moment.unix(item.createdAt / 1000).format('MMMM DD, YYYY')}
</Text>
<Text
style={[
this.ThemedStyles.videoMomentText,
{backgroundColor: this.ThemedColors[item.moment]},
]}>
{item.moment}
</Text>
</View>
<View style={this.ThemedStyles.videoMomentTagContaine}>
{item?.tagN?.map((data) => {
return (
<View>
<Text style={this.ThemedStyles.videoDateText}>
#{data}
</Text>
</View>
);
})}
</View>
</LinearGradient>
)}
</TouchableOpacity>
)}
</PlayerContext.Consumer>
);
When scrolling it works and playing videos for first 16 videos then it show black screen for next videos and not playing them. When scrolling back to previous videos they are still playing but videos after 16th are black.

How to not use null object?

I have object like this :
let collection = {
first: '',
second: '',
third: '',
Fourth: '',
};
My question is that, I use this in flatlist and some attributes come empty so I dont want to use them because when I put these to a box, they take up space.
How can I handle this ?
This is my code:
<View style={styles.container}>
<ScrollView>
<FlatList
data={this.state.AllMetarials}
extraData={this.state}
keyExtractor={(item, index) => index.toString()}
numColumns={1}
renderItem={ ({ item }) => {
return (
<View style={{ width: '50%', marginLeft: '2%', marginTop: '2%', alignItems: 'center', justifyContent: 'center', backgroundColor: '#00cec9', opacity: 0.7 }} >
<Text>{item.first}</Text>
<Text>{item.second}</Text>
<Text>{item.third}</Text>
<Text>{item.Fourth}</Text>
</View>
);
}}
/>
</ScrollView>
</View>
EDÄ°TED:
I did like this and it works
<View style={{ width: '50%', height: 80, marginLeft: '2%', marginTop: '2%', alignItems: 'center', justifyContent: 'center', backgroundColor: '#00cec9', opacity: 0.7 }} >
{item.first!== '' ? <Text> { item.first} </Text> : undefined}
{item.second!== '' ? <Text> { item.second} </Text> : undefined}
{item.third!== '' ? <Text> { item.third} </Text> : undefined}
{item.Fourth!== '' ? <Text> { item.Fourth} </Text> : undefined}
</View>
Your object can look like:
const myObject = {
first: '',
second: '',
}
Then you can use it as:
<View style={styles.container}>
<ScrollView>
<FlatList
data={this.state.AllMetarials}
extraData={this.state}
keyExtractor={(item, index) => index.toString()}
numColumns={1}
renderItem={ ({ item }) => {
return (
<View style={{ width: '50%', marginLeft: '2%', marginTop: '2%', alignItems: 'center', justifyContent: 'center', backgroundColor: '#00cec9', opacity: 0.7 }} >
{item.first && <Text>{item.first}</Text>}
{item.second && <Text>{item.second}</Text>}
{item.third && <Text>{item.third}</Text>}
{item.Fourth && <Text>{item.Fourth}</Text>}
</View>
);
}}
/>
</ScrollView>
</View>
In javascript && will make sure that the next statement is executed only when the evaluated value is not null, not empty, not zero or not undefined.

How to show Scrollview images horizontally having 2 columns

Hii i want to display images horizontally having 2 columns for this i am using scrollview but i dont know how to do that , i am using following code
code to fetch api
componentDidMount(){
return fetch('https://www.json-generator.com/api/json/get/ccLAsEcOSq?indent=1')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.book_array,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
code for render
render() {
if (this.state.isLoading === true) {
return <ActivityIndicator color={'red'} />;
}
return (
<View style={styles.container}>
<ScrollView horizontal={true}>
{this.state.dataSource.map(item => this.renderItem(item))}
</ScrollView>
</View>
);
}
}
code for renderItem
renderItem(item) {
return (
<View style={{ margin: 5 }}>
<View style={{
backgroundColor: 'red',
width: 150,
height: 150,
marginBottom: 1,
}}>
<Image style={{ width: 150,height: 150}}
source={{uri: item.image}}/>
</View>
<View style={{
backgroundColor: 'red',
width: 150,
height: 150,
marginBottom: 1,
}}>
<Image style={{ width: 150,height: 150}}
source={{uri: item.image}}/>
</View>
</View>
);}
Instead of ScrollView try FlatList which provides numColumns props which lets you allow to use columns as per your choice.
Instead of this,
<ScrollView horizontal={true}>
{this.state.dataSource.map(item => this.renderItem(item))}
</ScrollView>
Use this,
<FlatList
data={this.state.dataSource}
numColumns={2}
renderItem={this.renderItem}
/>
For more details of FlatList see Official Docs Here
Try flex-direction property:
renderItem(item) {
return (
<View style={{ margin: 5, flex: 1, flexDirection: "row", justifyContent: "space-around" }} >
<View style={{ backgroundColor: "red", width: 150, height: 150, marginBottom: 1 }} >
<Image style={{ width: 150, height: 150 }} source={{ uri: item.image }} />
</View>
<View style={{ backgroundColor: "red", width: 150, height: 150, marginBottom: 1 }} >
<Image style={{ width: 150, height: 150 }} source={{ uri: item.image }} />
</View>
</View>
);}
modify your ScrollView component Like this:
<ScrollView horizontal={true} contentContainerStyle={{height:300, flexWrap:'wrap'}}>
{this.state.dataSource.map(item => this.renderItem(item))}
</ScrollView>
Use flat list inside scroll view like this
<FlatList
horizontal={true}
data={this.state.dataSource}
renderItem={({ item }) => (this.renderItem({item}))}
/>
rearrange dataSource like this
array1 = [obj1,obj2,obj3,obj4,obj5,obj6,obj7,
array2=[[obj1,obj2],[obj3,obj4],[obj5,obj6],[obj7,obj8]]
and then render item with 2 rows.
didn't find any other way
To create view as you required need to implement your custom logic. In render function call a intermediate function to get columns in two row:
render() {
if (this.state.isLoading === true) {
return <ActivityIndicator color={'red'} />;
}
return (
<View style={styles.container}>
<ScrollView horizontal={true}>
{this.renderHorizantol(this.state.dataSource)}
</ScrollView>
</View>
);
In renderHorizantol function need to set up logic for even or odd rows, i am implementing this on index of dataSource Array:
renderHorizantol = (dataSource) =>{
let view = []
for(let i=0 ; i < data.length ; i = i+2)
{
let subView = this.renderItem(dataSource[i],dataSource[i+1])
view.push(subView)
}
return view
}
In renderItem function pass two element to draw upper and lower row contents:
renderItem(item1,item2) {
let image1 = item1["imageUrl"]
let image2 = item2 ? item2["imageUrl"] : null
return (
<View style={{ margin: 5 }}>
<View style={{
backgroundColor: 'red',
width: 150,
height: 150,
marginBottom: 1,
}}>
<Image style={{ width: 150,height: 150}}
source={{uri: image1}}/>
</View>
<View style={{
backgroundColor: 'red',
width: 150,
height: 150,
marginBottom: 1,
}}>
<Image style={{ width: 150,height: 150}}
source={{uri: image2}}/>
</View>
</View>
);}

Like functionality like Facebook react native

I am using a list of image.Below every image,there is a like button. When i click on the Like button, likes should be increases which is working fine. But it should work on the image I click. Currently it is increasing like count of all the images.I am new to react native.Any help would be appreciated.
Here, this is my code
export default class Art extends Component {
constructor(props) {
super(props)
this.state = {
value: null,
liked:false
}
}
_increaseValue(){
console.log(this.state.liked)
if (this.state.liked==false)
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value +1;
this.setState({value:newvalue})
}
else
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value -1;
this.setState({value:newvalue}
}
}
render() {
const datas = [
{
img: images[0]
},
{
img: images[1]
},
{
img: images[2]
},
{
img: images[3]
},
];
const { navigate } = this.props.navigation;
// eslint-disable-line
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data =>
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.value} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
/>
</Content>
);
}
}
You need to convert your Cards into separate components or store the like counts separately in state. You can approach this problem several ways. I'll give you an example of how you can achieve this behavior and you can implement it the way you like.
Example
export default class CutomListItem extends React.Component {
constructor(props) {
this.state = {
likes: 0
};
}
_increaseValue = () => {
this.setState((prevState) => {
return {
likes: prevState.likes++
};
});
}
render() {
const { data, navigate, share } = this.props; // send data with props
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.likes} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
}
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data => (<CutomListItem data={data} navigate={navigate} share={Share} />}
/>
</Content>
);
}

implement tabs in the center of the screen

I am new to react native. i have implemented stacknavigator inside drawernavigator. Using this library
"react-navigation": "^1.0.0-beta.11",
Now i want to implement tabs within the screen at the center. Following image is part of my screen
i dont have any idea how can i do this with any library or manually putting views.
Any help is appreciated.
Thanks
Well, I've solved that scenario using react-native-swiper
Basically you have to wrap all views you want to have inside a Swiper, render and style the header as you want.
Here there is a working example I've made:
render() {
return (
<View style={styles.body}>
<Swiper
height={500}
showsPagination={true}
loop={false}
renderPagination={this._renderPagination}
ref={component => this._swiper = component}>
<View style={styles.page}>
<FlatList data={..} renderItem={item => ...} keyExtractor={(item, index) => index} />
</View>
<View style={styles.page}>
<FlatList data={...} renderItem={item => ...} keyExtractor={(item, index) => index} />
</View>
<View style={styles.page}>
<FlatList data={...} renderItem={item => ...} keyExtractor={(item, index) => index} />
</View>
<View style={styles.page}>
<FlatList data={...} renderItem={item => ...} keyExtractor={(item, index) => index} />
</View>
</Swiper>
</View>
);
}
_renderPagination(index, total, context) {
return (
<View style={styles.pagination}>
{this._renderPaginationHeaders(index, total, context)}
</View>
)
}
_renderPaginationHeaders(index, total, context) {
let ret = [];
for (let i = 0; i < total; i++) {
ret.push(
<TouchableOpacity key={i} style={{ flex: 1, flexDirection: 'column' }} onPress={() => this._onPageChange(i)}>
<Text style={[styles.title, { flex: 1, textAlign: 'center', textAlignVertical: 'center' }]}>
{this._getSectionText(i)}
</Text>
<View style={{ height: 5, backgroundColor: index === i ? 'magenta' : 'transparent' }}></View>
</TouchableOpacity>
);
}
return ret;
}
_onPageChange(targetIndex) {
const currentIndex = this._swiper.state.index;
const offset = targetIndex - currentIndex;
this._swiper.scrollBy(offset);
}
const styles = StyleSheet.create({
body: {
flex: 1,
alignItems: 'center',
alignSelf: 'center',
backgroundColor: '#f1f1f1',
},
pagination: {
flexDirection: 'row',
width: Dimensions.get('window').width,
height: Header.currentHeight * 0.7,
backgroundColor: '#2E2E2E',
paddingLeft: 2,
paddingRight: 2,
alignItems: 'center',
position: 'absolute',
top: 0,
},
page: {
flex: 1,
marginTop: (Header.currentHeight * 0.7) + 3
},
title: {
color: 'white'
},
});