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

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.

Related

Possible Unhandled promise rejection TypeError: Network request failed, cannot read property 'map' of undefined

Recently started learning react-native and I'm following this tutorial on youtube, I'm trying to fetch flags and country codes from some websites api but I'm getting an error saying
Possible Unhandled promise rejection TypeError: Network request
failed, cannot read property 'map' of undefined
import {
View,
Text,
TouchableOpacity,
TouchableNativeFeedback,
Image,
TextInput,
Modal,
FlatList,
KeyboardAvoidingView,
ScrollView
} from "react-native";
import React from "react";
import LinearGradient from "react-native-linear-gradient";
import { COLORS, SIZES, FONTS, icons, images } from "../constants"
const SignUp = () => {
const [showPassword, setShowPassword] = React.useState(false);
const [areas, setAreas] = React.useState([]);
const [selectedArea, setSelectedArea] = React.useState(null);
const [modalVisible, setModalVisible] = React.useState(false);
React.useEffect(() => {
fetch("https://restcountries.eu/rest/v3.1/all")
.then(response => response.json())
.catch(err => {
console.log(err);
})
.then((data) => {
let areaData = data.map(item => {
return {
code: item.alpha2Code,
name: item.name,
callingCode: `+${item.callingCodes[0]}`,
flag: `https://countryflagsapi.com/png/${item.alpha2code}`
}
}).catch(err => {
console.log(err);
});
setAreas(areaData)
if (areaData.length > 0) {
let defaultData = areaData.filter(a => a.code == "US")
if (defaultData.length > 0) {
setSelectedArea(defaultData[0])
}
}
})
}, [])
function renderHeader() {
return (
<TouchableOpacity
style={{
flexDirection: "row",
alignItems: "center",
marginTop: SIZES.padding * 2,
paddingHorizontal: SIZES.padding * 2
}}
onPress={() => console.log("SignUp")}
>
<Image
source={icons.back}
resizeMode="contain"
style={{
width: 20,
height: 20,
tintColor: COLORS.white
}}
/>
<Text
style={{ marginLeft: SIZES.padding * 1.5, color: COLORS.white, ...FONTS.h4 }}
>Sign Up</Text>
</TouchableOpacity>
)
}
function renderLogo() {
return (
<View
style={{
marginTop: SIZES.padding * 5,
height: 100,
alignItems: 'center',
justifyContent: 'center'
}}
>
<Image
source={images.wallieLogo}
resizeMode="contain"
style={{
width: "60%"
}}
/>
</View>
)
}
function renderForm() {
return (
<View
style={{
marginTop: SIZES.padding * 3,
marginHorizontal: SIZES.padding * 3,
}}
>
{/* Full Name */}
<View
style={{
marginTop: SIZES.padding * 3,
}}
>
<Text
style={{
color: COLORS.lightGreen, ...FONTS.body3
}}
>Full Name</Text>
<TextInput
style={{
marginVertical: SIZES.padding,
borderBottomColor: COLORS.white,
borderBottomWidth: 1,
height: 40,
color: COLORS.white,
...FONTS.body3
}}
placeholder="Enter Full Name"
placeholderTextColor={COLORS.white}
selectionColor={COLORS.white}
/>
{/* Phone Number */}
<View style={{ marginTop: SIZES.padding * 2 }}>
<Text style={{ color: COLORS.lightGreen, ...FONTS.body3 }}>Phone Number</Text>
<View style={{ flexDirection: "row" }}>
{/* Country Code */}
<TouchableOpacity
style={{
width: 100,
height: 50,
marginHorizontal: 5,
borderBottomColor: COLORS.white,
borderBottomWidth: 1,
flexDirection: "row",
...FONTS.body2
}}
onPress={() => console.log("Show Modal")}
>
<View style={{ justifyContent: "center" }}>
<Image
source={icons.down}
style={{
width: 10,
height: 10,
tintColor: COLORS.white,
}}
/>
</View>
<View style={{ justifyContent: "center", marginLeft: 7 }}>
<Image
source={{ uri: selectedArea?.flag }}
resizeMode="contain"
style={{
width: 30,
height: 30
}}
/>
</View>
<View style={{ justifyContent: "center", marginLeft: 7 }}>
<Text style={{ color: COLORS.white, ...FONTS.body3 }}>{selectedArea?.callingCode}</Text>
</View>
</TouchableOpacity>
{/* Phone Number Input */}
<TextInput
style={{
flex: 1,
marginVertical: SIZES.padding,
borderBottomColor: COLORS.white,
borderBottomWidth: 1,
height: 40,
color: COLORS.white,
...FONTS.body3
}}
placeholder="Enter Phone Number"
placeholderTextColor={COLORS.white}
selectionColor={COLORS.white}
/>
</View>
</View>
{/* Password */}
<View style={{ marginTop: SIZES.padding * 2 }}>
<Text
style={{
color: COLORS.lightGreen,
...FONTS.body3
}}
>Password</Text>
<TextInput
style={{
marginVertical: SIZES.padding,
borderBottomColor: COLORS.white,
borderBottomWidth: 1,
height: 40,
color: COLORS.white,
...FONTS.body3
}}
placeholder="Enter Password"
placeholderTextColor={COLORS.white}
selectionColor={COLORS.white}
secureTextEntry={!showPassword}
/>
<TouchableOpacity
style={{
position: "absolute",
right: 0,
bottom: 10,
height: 30,
width: 30
}}
onPress={() => setShowPassword(!showPassword)}
>
<Image
source={showPassword ? icons.disable_eye : icons.eye}
style={{
height: 20,
width: 20,
tintColor: COLORS.white
}}
/>
</TouchableOpacity>
</View>
</View>
</View>
)
}
function renderButton() {
return (
<View style={{ margin: SIZES.padding * 3 }}>
<TouchableOpacity
style={{
height: 60,
backgroundColor: COLORS.black,
borderRadius: SIZES.radius / 1.5,
alignItems: "center",
justifyContent: "center"
}}
onPress={() => console.log("Let's Go")}
>
<Text style={{ color: COLORS.white, ...FONTS.h3 }}>Continue</Text>
</TouchableOpacity>
</View>
)
}
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : null}
style={{ flex: 1 }}
>
<LinearGradient
colors={[COLORS.lime, COLORS.emerald]}
style={{ flex: 1 }}
>
<ScrollView>
{renderHeader()}
{renderLogo()}
{renderForm()}
{renderButton()}
</ScrollView>
</LinearGradient>
</KeyboardAvoidingView>
)
}
export default SignUp;
Saw an old post regarding this issue but the solution of adding catch(err didn't work please any suggestions
The problem you faced mainly occurs in the fetch() inside useEffect().
To handle the any potential errors in function, we will use catch() as #caslawter mentioned.
fetch("https://restcountries.eu/rest/v3.1/all")
.then(response => response.json())
.then((data) => {
//... Do what you want after fetch data
})
.catch(err => {
//Any error occurs in json parsing or after fetching data will jump to here
console.log(err);
})
Also, please make sure your data is not undefined before you apply 'map' function to it.

Ref in flatlist items does not return correct PageY position when loading more data in a list

I am trying to display dropdown below flatlist items. Pagination is implemented in Flatlist, so when i load data for first-page, the dropdown position is calculated accurately. but when i load data for another pages, pageY postion in ref measure method is increased by list size. So due to this dropdown isn't displayed in visible area. I am attaching my code for reference.
this is my render method.
render() {
let { list, } = this.props;
const {top,listVisibity,articleDropdown} = this.state;
return (
<View style={{flex:1}}>
<OptimizedFlatList
maxToRenderPerBatch={10}
windowSize={16}
onEndReached={() => this.onEndReached()}
nestedScrollEnabled={false}
onScrollBeginDrag = {() => this.setState({listVisibity:false})}
onEndReachedThreshold={Platform.OS === 'ios' ? 0 : 0.01}
onMomentumScrollBegin={() => { this.onEndReachedCalledDuringMomentum = false; }}
data={list}
renderItem={({ item }) => this._renderItem(item)}
keyExtractor={item => item.id}
style={{ flexGrow: 1}}
ListFooterComponent={this.footer}
/>
</view>
}
And here is list and sublist rendering
_renderItem = item => {
return (
<View style={styles.container}>
<ShadowView style={styles.shadowStyle}>
<View style={styles.listItem} >
<View style={{ flex: 0.6, flexDirection: 'row' }}>
<Image
source={constants.images.dot}
style={{ alignSelf: 'center', width: RFValue(12), resizeMode: 'contain', marginRight: 10 }}
/>
<Highlighter
highlightStyle={{backgroundColor: 'yellow'}}
searchWords={[this.props.searchedText]}
textToHighlight= {item.name.toUpperCase()+" ("+item.topics.length+")"}
style={{ color: "#0C3C7F", alignSelf: 'center', fontWeight: '500', fontFamily:constants.fontFamily.SFProDisplay }}
/>
</View>
<View style={{ flex: 0.4}}>
<TouchableOpacity onPress={() => {
this.updateSelection(item)
}}>
{item.isExpanded ? <Image
source={constants.images.dropdownArrow}
style={{ alignSelf: 'flex-end', resizeMode: 'contain' }}
/> :
<Image
source={constants.images.arrowUp}
style={{ alignSelf: 'flex-end', resizeMode: 'contain' }}
/>
}
</TouchableOpacity>
</View>
</View>
</ShadowView>
{this.renderSubList(item)}
</View>
);
}
renderSubList = (item) => {
return <Collapsible collapsed={!item.isExpanded}>
<FlatList
data={item.topics}
scrollEnabled={false}
renderItem={({ item }) => (
<ShadowView style={item.isSelected? styles.topicShadowStyle_1:styles.topicShadowStyle}>
<View ref={ref => this.parentView = ref}
onLayout={(event) => {
this.find_dimesions(event.nativeEvent.layout) }}
style={[{flexDirection: 'row'}, item.isSelected ? { borderColor: constants.colors.lightBlue, borderTopLeftRadius: 10,borderBottomLeftRadius: 10,borderRadius:8, borderWidth: 2 } : {}]}>
{(item.fullTextUrl!=null && item.fullTextUrl!='') || (item.pdfLink!=null && item.pdfLink!='') ?
<View style={{ width: width * 4 / 100, backgroundColor: constants.colors.lightBlue, borderTopLeftRadius: 8, borderBottomLeftRadius: 8 }}></View>:
<View style={{ width: width * 4 / 100, backgroundColor: constants.colors.lightGray_1, borderTopLeftRadius: 8, borderBottomLeftRadius: 8 }}></View>
}
<View style={{ width: '95%' }}>
<TouchableWithoutFeedback onLongPress={() => this.props.updateShowSelectedIcon(item)} onPress={() => this.props.showDetails(item)}>
<View style={{ flexDirection: 'row', width: '100%' }}>
<View style={{ flex: 1, marginHorizontal: width * 3 / 100, marginVertical: height * 1.5 / 100, backgroundColor: constants.colors.white }}>
<View style={{ flexDirection: 'row', width: '100%' }}>
<View style={{ alignContent: 'flex-start', width: '65%' }}>
<Highlighter
highlightStyle={{backgroundColor: 'yellow'}}
searchWords={[this.props.searchedText]}
textToHighlight= {item.journal.toUpperCase()}
style={styles.jurnalTitle}
numberOfLines={2}
/>
</View>
<View style={{ alignContent: 'flex-end', width: '35%', }}>
<Text style={styles.dateStyle} >{item.date}</Text>
</View>
</View>
<View style={{ flexDirection: 'row', width: '100%', marginTop: height * 1 / 100 }}>
<View style={{ alignItems: 'flex-start', width: '70%' }}>
<Highlighter
highlightStyle={{backgroundColor: 'yellow'}}
searchWords={[this.props.searchedText]}
textToHighlight= {item.article}
style={{ fontWeight: 'bold', color: constants.colors.black_1, alignContent: 'flex-start' }}
numberOfLines={2}
/>
</View>
{!this.props.showSelectedIcon?
<View
ref={(ref) => { this.rowRefs[item.id] = ref; }}
// ref={ref => this[`myView${item.id}`]=ref}
onLayout={(event) => {
const {x, y, width, height} =event.nativeEvent.layout
}}
style={{position:'relative', alignItems: 'flex-end', width: '30%' }}>
<TouchableOpacity style={{ height: RFValue(20), width: RFValue(20) }}
onPress={() => this.calculateIconPosition(item)}>
{(item.fullTextUrl!=null && item.fullTextUrl!='') || (item.pdfLink!=null && item.pdfLink!='') ?
<Image
source={constants.images.Oval}
style={{ height: RFValue(20), width: RFValue(20) }}
/>:
<Image
source={constants.images.dropdown}
style={{ height: RFValue(20), width: RFValue(20) }}
/>
}
</TouchableOpacity>
{/* { <View onLayout={(event) => {
const {x, y, width, height} =event.nativeEvent.layout
console.log(y)
}} > </View>} */}
</View>:
<View
style={{ alignItems: 'flex-end', width: '30%' }}>
{item.isSelected?
<Image
source={constants.images.selected}
style={{ height: RFValue(20), width: RFValue(20) }}
/>:
<Image
source={constants.images.unselect}
style={{ height: RFValue(20), width: RFValue(20) }}
/>
}
</View>
}
</View>
</View>
</View>
</TouchableWithoutFeedback>
{this.renderNotesView(item)}
</View>
</View>
</ShadowView>
)}
keyExtractor={item => item.id}
/>
</Collapsible>
}
Item Measurement Method Call
calculateIconPosition = (item) => {
this.rowRefs[item.id].measure( (fx, fy, width, height, px, py) => {
console.log("=================PY=====================")
console.log(py)
})
}
Is there any way to get exact pageY position in flat list.

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 Use if in FlatList

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.

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>
);}