I am quite new to react native. I have created a FlatList for rendering this list of items, however, it is not scrolling. I've googled it for hours and tried nearly everything suggested in stack overflow threads - removed flex, added flex, wrapped it in a view, but nothing seems to work.
Here is my code (the issue is in the second FlatList) -
return(
<View style = {{ height: '100%' }}>
<View style = {{ width: '100%' }}>
<AppHeader />
</View>
<View style = {{ width: '100%'}}>
<View style = {{ width: '70%', alignSelf: 'center', flex: 1 }}>
<View>
<FlatList
data = {this.getTodayDay()}
renderItem = {this.renderItemDays}
keyExtractor = {this.keyExtractor}
/>
</View>
<FlatList
data = {this.getVisibleHours()}
renderItem = {this.renderItem}
keyExtractor = {this.keyExtractor}
scrollEnabled = {true}
/>
</View>
</View>
</View>
this.renderItem -
renderItem = () => {
// irrelevant code
if( isClass === true ){
return(
<ListItem bottomDivider = {true} style = {styles.renderItemActiveClass}>
<ListItem.Content>
<TouchableOpacity
onPress = {()=>{
this.props.navigation.navigate('ClassDetailsScreen', { "data": classData })
}}>
<ListItem.Title>{ definiteClassTime }</ListItem.Title>
<ListItem.Subtitle>{ classData.class_name }</ListItem.Subtitle>
</TouchableOpacity>
</ListItem.Content>
</ListItem>
)
}
else{
return(
<ListItem bottomDivider = {true} style = {styles.renderItemClass}
containerStyle = {styles.renderItemContent}>
<ListItem.Content>
<ListItem.Title>{item}:00</ListItem.Title>
<ListItem.Subtitle>No Class</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
)
}
}
the StyleSheet -
renderItemClass: {
borderColor: 'purple',
borderWidth: 2
},
renderItemActiveClass: {
borderColor: 'green',
borderWidth: 2
},
renderItemContent: {
},
Could somebody please tell me what I'm doing wrong?
Add a height to both the flatlist. And also wrap your second flatlist within a seperate view. Here is an example:
return (
<View style={{ height: "100%" }}>
<View style={{ width: "100%" }}>
<AppHeader />
</View>
<View style={{ width: "100%" }}>
<View style={{ width: "70%", alignSelf: "center", flex: 1 }}>
<View style={{ height: 60, alignSelf: "center" }}>
<FlatList
data={this.getTodayDay()}
renderItem={this.renderItemDays}
keyExtractor={this.keyExtractor}
/>
</View>
<View style={{ height: 60, alignSelf: "center" }}>
<FlatList
data={this.getVisibleHours()}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
scrollEnabled={true}
/>
</View>
</View>
</View>
</View>
);
I have a list of cards,
when pressed to any of them, I want to Increase hight for that card,
So I use layoutAnimation to handle this case because when I use Animated API from RN, I got an error when setNativeDrive "height"
Anyway,
In my case, it increases height for every card in the list,
So how can I solve it?
Code snippet
Live Demo
const OpenedAppointments = ({slideWidth}) => {
const [currentIndex, setCurrentIndex] = React.useState(null);
const [cardHeight, setCardHeight] = useState(140);
const collapseCard = (cardIndex) => {
setCurrentIndex(cardIndex);
currentIndex === cardIndex
? (LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut),
Animated.spring(),
setCardHeight(200))
: (LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut),
Animated.spring(),
setCardHeight(140));
};
const renderItems = (item, index) => {
return (
<TouchableOpacity
delayPressIn={0}
onPress={() => collapseCard(index)}
key={item.id}>
<Animated.View
style={[
styles.itemContainer,
{
height: cardHeight,
},
]}>
<View style={styles.headerContainer}>
<View style={styles.imgContainer}>
<Image
resizeMode="cover"
style={styles.img}
source={{uri: item.vendorInfo.vendorImg}}
/>
</View>
<View style={{width: '80%'}}>
<View style={styles.titleContainer}>
<Text numberOfLines={1} style={styles.vendorName}>
{item.vendorInfo.name}
</Text>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={styles.rateText}>{item.vendorInfo.rate}</Text>
<AntDesign name="star" size={18} color="#262626" />
</View>
</View>
<View style={styles.socialContainer}>
<View
style={{
width: 32,
height: 32,
backgroundColor: '#000',
borderRadius: 5,
}}
/>
</View>
</View>
</View>
<View style={styles.footer}>
<Text style={styles.serviceName}>
{item.serviceName}
</Text>
<Text style={styles.price}>
{item.price}
</Text>
</View>
// this will appeared when pressed to card "Footer Card"
<View>
<View style={styles.line} />
<View style={styles.editFooter}>
<View style={styles.dateContainer}>
<MemoCalender
style={styles.calenderIcon}
size={26}
color="#000"
/>
<View style={styles.dateBox}>
<Text style={styles.dateText}>{item.date}</Text>
<Text style={styles.dateText}>{item.time}</Text>
</View>
</View>
</View>
</View>
</Animated.View>
</TouchableOpacity>
);
};
return(
<>
{Data.opened.map((item, index) => renderItems(item, index))}
</>
);
}
Change this:
<Animated.View
style={[
styles.itemContainer,
{
height: cardHeight,
},
]
>
{...}
</Animated.View>
by
<Animated.View
style={[
styles.itemContainer,
{
height: currentIndex === index ? cardHeight : 140,
},
]
>
{...}
</Animated.View>
If you want to be more efficient, the default height of your card, define it in a constant (ex: const = DEFAULT_CARD_HEIGHT = 140) and use this constant wherever you use 140 as card height
I am working on a react native application. I have to show multiple images. My code is:
render() {
if (!this.props.data) {
return(<Text style={styles.noIMG}>Keine Bilder vorhanden</Text>)
}
return (
<View>
<View style={styles.view}>
{
(
this.props.data == '' ||
this.props.data == null ||
this.props.data == undefined
) ? null :
this.props.data.map(img => {
console.log(img.image);
console.log("Image displayed");
return(
<TouchableHighlight
key={this.uuidv4()}
onPress={()=>{
this.setState({zoom: img.image})
}}
>
<Image
style={styles.imagePreview}
source={{uri: img.image}}
/>
</TouchableHighlight>)
})
}
</View>
{ this.state.zoom ?
<Card>
<PinchZoomView scalable={false}>
<FitImage resizeMode="contain" source={{uri: this.state.zoom}}/>
</PinchZoomView>
<TouchableOpacity
style={styles.btn}
onPress={() => this.deleteImage(this.state.zoom)}>
<Text style={{color:'white'}}>Delete Image</Text>
</TouchableOpacity>
</Card> :
<View style={styles.container}><Text>Bild zum vergrößern antippen.</Text></View>
}
</View>
);
}
I do get two images in "props.data" but on screen only one image is displayed. The css code is:
const styles = StyleSheet.create({
imagePreview:{
width: 100,
height: 100,
margin: 5
}
});
render() {
return (
<View style={{ flex: 1, flexDirection:'row'}}>
{data.map((value, i) => {
return (
<View key={i}>
<TouchableOpacity>
<Image
source={{ uri: value.imageUrl }}
style={{ width: 50, height: 50 }}
resizeMode={"stretch"}
/>
</View>
</TouchableOpacity>
);
})}
</View>
);
}
Try using a FlatList
<FlatList
data={this.props.data}
extraData={this.state}
renderItem={({ item }) => {
return (
<View>
<TouchableOpacity onPress={() => this.setState({zoom: img.image})}>
<Image
source={{ uri: item.image }}
PlaceholderContent={<ActivityIndicator />}
/>
</TouchableOpacity>
</View>
)
}}
keyExtractor={(item, index) => index.toString()}
/>
I am getting below value in the props "ticketDetailsInfo" and after that I am taking followupDetails array ,below is the value of followupDetails which is coming from server . ,but when amd doing maping followupDetails.map() its throwing error followupDetails.map() is not a function . While I have to take array value and display in ui . Please correct me where I am going wrong .
// Array Value is
const{ticketDetailsInfo}=this.props
const{troubleTicketDetails,workFlowDetails,followupDetails} =ticketDetailsInfo;
"followupDetails": [
{
"INCIDENTNUMBER": "16739",
"INCIDENTINITIATOR": "U",
"INCIDENTTIMESTAMP": "06/06/2019 16:25:36",
"NOTES": "Test",
"USERID": "597",
"STATUSUPDATED": null,
"USERGROUPNAME": "clmui",
"BINARYOBJECT": "N"
},
{
"INCIDENTNUMBER": "16738",
"INCIDENTINITIATOR": "E",
"INCIDENTTIMESTAMP": "06/06/2019 16:25:36",
"NOTES": "Test",
"USERID": "597",
"STATUSUPDATED": null,
"USERGROUPNAME": "clmui",
"BINARYOBJECT": "N"
}
],
import React, { Component } from 'react';
import { ImageBackground, ScrollView } from 'react-native';
import { Body, Button, Card, CardItem, Text, View } from 'native-base';
import styles from '../requestTab/TroubleTicketDetails.style';
import Header from '../../ui/header';
import BG from '../../../images/bg.jpg';
import { IconNormal } from '../../ui/icons';
import _ from 'lodash';
import { RegularText, SmallText } from '../../ui/text';
import StepIndicator from 'react-native-step-indicator';
import LoadingSpinner from '../../ui/spinner';
class TroubleTicketDetails extends Component {
constructor(props) {
super(props);
const {MSISDN,ticketDetailsInfo} = this.props;
this.state = {
title: 'Trouble Ticket',
icon: "sim",
mobile: MSISDN,
StepsVaue:[],
Steplabels:[],
currentStepPosition:[],
SteplabelconcatValue:[],
SteplabelsTimes:[]
};
}
iconSymbol = (priority) => {
let symbol = '';
let color = '';
if (priority === '10') {
symbol = 'exclamation';
color = 'red';
} else if (priority === '1') {
symbol = 'arrowdown';
color = 'white';
} else {
symbol = '';
color = '';
}
return { symbol: symbol, color: color };
};
componentDidMount() {}
componentDidUpdate(prevProps, prevState, snapshot) {}
componentDidCatch(error, errorInfo) {
console.log("TroubleTicketHistory Error", error);
console.log("TroubleTicketHistory ErrorInfo", errorInfo);
}
loadScreen() {
//RedirectScreen(this.props.navigation, 'SimSwap', this.state);
}
renderLabel = ({ position, stepStatus, SteplabelsTimes, currentPosition }=this.state) => {
return (
<Text
style={
position === currentPosition ? styles.stepLabelSelected : styles.stepLabel
}
>
{SteplabelsTimes}
</Text>
)
}
render() {
let { title, mobile, icon, currentStepPosition, Steplabels } = this.state;
let { navigation,ticketDetailsInfo,referenceNumber,TICKET_TYPE_DESCRIPTION,priority, currentStatus,convertedDate } = this.props;
const{troubleTicketDetails,workFlowDetails,followupDetails} =ticketDetailsInfo;
console.log("followupDetails" , followupDetails)
StepsVaue = workFlowDetails.currentNextActivity;
Steplabels = StepsVaue.map(StepsVaue => {
return StepsVaue._activityName;
});
SteplabelsTimes = StepsVaue.map(StepsVaue => {
return StepsVaue._maxHoldTime;
});
// SteplabelconcatValue = StepsVaue.map(StepsVaue => {
// return StepsVaue._activityName.concat("_",StepsVaue._maxHoldTime);
// });
currentStepPosition = StepsVaue.filter((item) => {
return item._activityStatus === "I"
});
const stepIndicatorStyles = {
stepIndicatorSize: 30,
currentStepIndicatorSize:40,
separatorStrokeWidth: 1,
currentStepStrokeWidth: 5,
stepStrokeCurrentColor: '#fe7013',
separatorFinishedColor: 'black',
separatorUnFinishedColor: 'black',
stepIndicatorFinishedColor: 'green',
stepIndicatorUnFinishedColor: '#aaaaaa',
stepIndicatorCurrentColor: '#ffffff',
stepIndicatorLabelFontSize: 0,
currentStepIndicatorLabelFontSize: 0,
stepIndicatorLabelCurrentColor: '#000000',
stepIndicatorLabelFinishedColor: '#ffffff',
stepIndicatorLabelUnFinishedColor: 'rgba(255,255,255,0.5)',
labelColor: 'black',
labelSize: 15,
currentStepLabelColor: 'black'
}
if(!_.isEmpty(referenceNumber) && (StepsVaue[0])) {
return (
<ImageBackground source={BG} style={styles.imgBG}>
<ScrollView>
<View style={styles.container}>
<View>
<Header title={title} subtitle={mobile} icon={icon} navigation={navigation}/>
</View>
<View style={styles.contentContainer}>
<View style={{ padding: 10 }}>
<View style={{marginBottom: 10}}>
<Card>
<CardItem header style={{backgroundColor: '#23476B', width: '100%', justifyContent: 'space-between'}}>
<View style={{flexDirection:'column'}}>
<View>
<RegularText text={`${TICKET_TYPE_DESCRIPTION} ID : ${referenceNumber}`} textColor='#fff' style={{ fontWeight: 'bold' }}/>
</View>
<View>
<SmallText text={`Raised ${convertedDate}`} textColor="#fff"/>
</View>
</View>
<View style={{flexDirection:'row'}}>
<View style={{flexDirection:'row'}}>
<IconNormal icon={this.iconSymbol(priority).symbol} type="AntDesign" style={{ color: this.iconSymbol(priority).color , paddingTop: 5}}/>
</View>
{/* <IconNormal icon={this.iconSymbol(priority).symbol} type="AntDesign" style={{ color: this.iconSymbol(priority).color , paddingTop: 5}}/> */}
<View style={{backgroundColor:'orange', borderRadius:50,height: 28, paddingRight: 10, paddingLeft: 10, paddingTop: 5}}>
<SmallText text={`${currentStatus}`} textColor='white'/>
</View>
</View>
</CardItem>
<CardItem>
<Body>
<View style={{flexDirection:'row', justifyContent: 'space-between', width: '100%'}}>
{/* <View style={{flexDirection:'column'}}>
<View>
<SmallText text="Catagory" textColor="grey"/>
</View>
<View>
<Text style={{ fontWeight: 'bold', fontSize:14 }}>{troubleTicketDetails.cat1}</Text>
</View>
</View> */}
{troubleTicketDetails.cat2.length > 0 &&
<View style={{flexDirection:'column'}}>
<View>
<SmallText text="Sub-Category" textColor="grey"/>
</View>
<View>
<Text style={{ fontWeight: 'bold', fontSize:14 }}>{troubleTicketDetails.cat2}</Text>
</View>
</View>}
{troubleTicketDetails.cat3.length > 0 &&
<View style={{flexDirection:'column'}}>
<View>
<SmallText text="Sub-SubCategory" textColor="grey"/>
</View>
<View>
<Text style={{ fontWeight: 'bold', fontSize:14 }}>{troubleTicketDetails.cat3}</Text>
</View>
</View>}
</View>
</Body>
</CardItem>
</Card>
</View>
<View>
<RegularText text={`WORKFLOW`} textColor='grey' style={{ fontWeight: 'bold', textAlign:'center', marginBottom:10 }}/>
</View>
<View style={{borderWidth:1, borderColor:'lightgrey', borderBottomColor:'white', padding:10, flexDirection:'column'}}>
<Card>
<CardItem>
<Body style={{justifyContent: 'center', alignItems: 'center'}}>
<View style={{flexDirection:'column'}}>
<RegularText text={` ${workFlowDetails.WRKFLW_DESC_V}`} textColor='green' style={{ fontWeight: 'bold' }}/>
</View>
<View style={{flexDirection:'column'}}>
<SmallText text={`Time Remaining is ${workFlowDetails.ESTIMATED_RESOLN_TM_N} Hours`} textColor='green' style={{ fontWeight: 'bold' }}/>
</View>
</Body>
</CardItem>
</Card>
</View>
<View style={{paddingLeft:10, height:300, marginBottom:10, borderWidth:1, borderColor:'lightgrey', borderTopColor:'white'}}>
<StepIndicator
customStyles={stepIndicatorStyles}
currentPosition={currentStepPosition.length}
stepCount={Steplabels.length}
labels={Steplabels}
renderLabel ={this.renderLabel()}
direction="vertical"
/>
</View>
<View>
<RegularText text={`NOTES`} textColor='grey' style={{ fontWeight: 'bold', textAlign:'center', marginBottom:10 }}/>
</View>
<View style={{marginLeft:10,marginRight:10}}>
{Array.isArray(followupDetails) && followupDetails.map(
({ INCIDENTINITIATOR, INCIDENTTIMESTAMP,NOTES, USERGROUPNAME}, index) => {
var INCIDENTINITIATOR_Value;
if(INCIDENTINITIATOR =="U"){
INCIDENTINITIATOR_Value ="USER";
}
else{
INCIDENTINITIATOR_Value ="CUSTOMER";
}
<View style={{marginBottom: 10}} key={index}>
<Card>
<CardItem header style={{backgroundColor: '#fff', justifyContent: 'space-between', borderBottomColor: '#f1f1f1', borderBottomWidth: 1}}>
<View style={{flexDirection:'column'}}>
<View style={{backgroundColor:'lightgrey', borderRadius:50,height: 28, paddingRight: 10, paddingLeft: 10, paddingTop: 5}}>
<SmallText text={`${INCIDENTINITIATOR_Value}`} textColor='grey'/>
</View>
<View>
<Text style={{ fontSize:14 }}> {NOTES} </Text>
</View>
</View>
</CardItem>
<CardItem>
<Body>
<View style={{flexDirection:'row', justifyContent: 'space-between', width: '100%'}}>
<View>
<SmallText text={`${USERGROUPNAME}`} textColor="grey"/>
</View>
<View>
<SmallText text={`${INCIDENTTIMESTAMP}`} textColor="grey"/>
</View>
</View>
</Body>
</CardItem>
</Card>
</View>
})
}
</View>}
{/* <Button block bordered dark>
<Text>Add a Note</Text>
</Button> */}
</View>
</View>
</View>
</ScrollView>
</ImageBackground>
);
}else{
return(
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<LoadingSpinner color="#00678F"/>
</View>
)
}
}
}
/*<IconNormal icon={this.iconSymbol(priority).symbol} type="AntDesign" style={{ color: this.iconSymbol(priority).color , paddingTop: 5}}/> */
export default TroubleTicketDetails;
Thanks
To iterate and add views dynamically from array, I'm using following code.
export default class CreateFeedPost extends Component {
constructor(props) {
super(props);
this.state = {
selectedImages: ["1", "2", "3"]
};
}
render() {
let animation = {};
let color = Platform.OS === "android"
? styleUtils.androidSpinnerColor
: "gray";
return (
<View style={{ flex: 1, flexDirection: "column" }}>
<View style={styles.topView}>
<View style={styles.closeButtonView}>
<TouchableHighlight
underlayColor="transparent"
style={styles.closeButton}
onPress={this._closeButtonClicked.bind(this)}
>
<Icon name="times" color="#4A4A4A" size={20} />
</TouchableHighlight>
</View>
<View style={styles.postButtonView}>
<TouchableHighlight
underlayColor="transparent"
style={styles.postButton}
onPress={this._postButtonClicked.bind(this)}
>
<Text style={styles.postButtonText}>Post</Text>
</TouchableHighlight>
</View>
</View>
<View style={styles.profileContainer}>
<View style={{ width: 65, height: 65, padding: 10 }}>
<Image
source={{ uri: global.currentUser.USER_PROFILE_PIC }}
style={styles.profileImage}
/>
</View>
<View style={[styles.middleTextView]}>
<Text style={[styles.memberName]}>
{global.currentUser.USER_NAME}
</Text>
</View>
</View>
<Animated.ScrollView
style={{ flex: 1 }}
scrollEventThrottle={1}
showsVerticalScrollIndicator={false}
{...animation}
>
<View>
<TextInput
ref="postTextInputRef"
placeholder="So, What's up?"
multiline={true}
autoFocus={true}
returnKeyType="done"
blurOnSubmit={true}
style={styles.textInput}
onChangeText={text => this.setState({ text })}
value={this.state.text}
onSubmitEditing={event => {
if (event.nativeEvent.text) {
this._sendCommentToServer(event.nativeEvent.text);
this.refs.CommentTextInputRef.setNativeProps({ text: "" });
}
}}
/>
</View>
</Animated.ScrollView>
<KeyboardAvoidingView behavior="padding">
<ScrollView
ref={scrollView => {
this.scrollView = scrollView;
}}
style={styles.imagesScrollView}
horizontal={true}
directionalLockEnabled={false}
showsHorizontalScrollIndicator={false}
decelerationRate={0}
snapToInterval={100}
snapToAlignment={"start"}
contentInset={{
top: 0,
left: 0,
bottom: 0,
right: 0
}}
>
{this.state.selectedImages.map(function(name, index) {
return (
<View style={styles.imageTile} key={index}>
<View style={styles.imageView}>
<TouchableHighlight
underlayColor="transparent"
style={styles.imageRemoveButton}
onPress={() => this._imageRemoveButtonClicked.bind(this)}
>
<Icon name="times" color="#4A4A4A" size={20} />
</TouchableHighlight>
</View>
</View>
);
})}
</ScrollView>
<TouchableHighlight
underlayColor="transparent"
style={styles.cameraButton}
onPress={this._cameraButtonClicked.bind(this)}
>
<View style={styles.cameraButtonView}>
<Icon name="camera" color="#4A4A4A" size={20} />
<Text style={styles.cameraButtonText}>Add Pic</Text>
</View>
</TouchableHighlight>
</KeyboardAvoidingView>
</View>
);
}
_closeButtonClicked() {
this.props.navigator.pop();
}
_postButtonClicked() {}
_cameraButtonClicked() {
this.props.navigator.push({
title: "All Photos",
id: "photoBrowser",
params: {
limit: 3,
selectedImages: this.state.selectedImages
}
});
}
_imageRemoveButtonClicked() {
console.log("yes do it");
}
}
I'm loading code in the render method. If I write the function imageRemoveButtonClicked outside render method, it's giving an error saying that 'Cannot read property bind of undefined'. Don't know what to do. Can some one please help me in this.
Use arrow functions and class property feature. For more information about binding patterns read this article. Try to add your method as:
export class App extends Component {
yourMapFunction = () => {
yourCode...
}
}
I believe the problem is that you are not using an arrow function as the argument to this.state.selectedImages.map(). If you want to access this inside an inner function, you should use the arrow function syntax. The standard syntax does not capture this.
this.state.selectedImages.map((name, index) => {
return (...);
})