I want to create a Infinite ScrollView like react-native-infinte-scrollview in which views are created and deleted on scroll but this plugin doesn't provide next/previous buttons. I just want to add next and previous buttons because I have 10 gif files in my project and each gif is 7 to 10 MB in size and if I load all these gif files at the same time in scrollview, my app crashed.
i dont know about this but i have logic here
constructor(){
this.state = {
pageNUmber:0,
data:['url1','url2',url3]
}
}
renderGif(){
var data = this.state.data;
return(
<Image source={{uri:data[this.state.pageNUmber]}} ?>
)
}
changePage(val){
if(val=='next'){
this.setState({
pageNumber:this.state.pageNumber+1
})
}else{
if(this.state.pageNumber!=0)
this.setState({
pageNumber:this.state.pageNumber-1
})
}
}
render(){
return(
<View>
<ScrollView>
{this.renderGif()}
</ScrollView>
<TouchableOpacity onPress={()=>{this.changePage('next')}}>
<Text>next</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>{this.changePage('previous')}}>
<Text>previous</Text>
</TouchableOpacity>
</View>
)
}
Im pretty sure that the difference between React Native's ScrollView and FlatList is that flatlist deletes content off the page.
According to the Docs, you'll want to use Flatlist with horizontal enabled
Related
I have a question. I have a loader and during the loading I would show three different texts. Like text1, then this disappear and it's show text2 and then text3.
<View style={style.container}>
<View style={style.page}>
<ActivityIndicator size="large" color="#56cbbe" />
<Text>Text1.. </Text>
<Text>Text2.. </Text>
<Text>Text3.. </Text>
</View>
</View>
In this case I only show the three texts together. How can I do?
Thank you :)
One way to solve this is to use setInterval and call update function to loop through the texts assuming if they are present in form of array.
Simply saying for example.
Let's maintain loadingText in state as loadingText: ['text1', 'text2', 'text3'],A variable to track the present item as currentLoadingTextIndex: 0 and call setInterval in componentDidUpdate.
Be careful when calling update function in here,as one wrong mistake will make your app crash.
componentDidUpdate(prevProps, prevState) {
if (!prevState.isLoading && this.state.isLoading) {
this.timerId = setInterval(this.changeLoadText, 2000);
} else if (prevState.isLoading && !this.state.isLoading) {
clearInterval(this.timerId);
}
}
and finally our update function
changeLoadText = () => {
this.setState(prevState => {
return {
currentLoadingTextIndex:
(prevState.currentLoadingTextIndex + 1) %
prevState.loadingText.length,
};
});
};
I am attaching a working expo Demo for clarity purpose.
What you want is to show indicator and text1 during loading time and then text2 and text3. Is that right?
So I made an example for you. This should solve the problem by changing the status value. You can display the indicator for the duration of loading and show the text by changing the status value when loading is complete.
Example Code
//This is an example code to understand ActivityIndicator//
import React from 'react';
//import react in our code.
import { ActivityIndicator, Button, View, StyleSheet,Text } from 'react-native';
//import all the components we are going to use.
export default class App extends React.Component {
state = { showIndicator: true };
componentDidMount() {
setTimeout(() => {this.setState({showIndicator: false})}, 2000)
}
onButtonPress = () => {
//function to change the state to true to view activity indicator
//changing state will re-render the view and indicator will appear
};
render() {
//Check if showIndicator state is true the show indicator if not show button
if (this.state.showIndicator) {
return (
<View style={styles.container}>
{/*Code to show Activity Indicator*/}
<ActivityIndicator size="large" color="#0000ff" />
<Text>Text1.. </Text>
{/*Size can be large/ small*/}
</View>
);
} else {
return (
<View style={styles.container}>
<Text>Text2.. </Text>
<Text>Text3.. </Text>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
flexDirection: 'column',
alignItems: "center"
},
});
On pressing the button(ButtonComponent), the state of the button gets changed. Now I'm passing that state to the <FlatListItem> (a child component ) inside <FlatList>. Depending on that status, the each item in the <FlatList> should be re-arranged.
I just got to know about this extraData prop but not sure how to make use of it in the code.
It's not something new but it is like simple checkbox implementation.
Everything is working fine but when I press the select all button all the remaining select buttons are not getting toggled to selected.
class FlatListItem extends Component{
constructor(props){
super(props)
const{ isSelected }=this.props
this.state={
selectedStatus:isSelected,
}
}
changeSelectStatus=(key)=>{
this.setState({selectedStatus:!this.state.selectedStatus});
return key;
}
render(){
return(
<View style={{flex:1,
flexDirection:'row',
backgroundColor:'white'}}>
<View>
<Image
source={{uri:this.props.item.imageUri}}
style={{width:50, height:50, margin:5}}>
</Image>
</View>
<View>
<Text style={{color:'black', padding:10, fontSize:16}}>{this.props.item.name}</Text>
</View>
<View style={{flex:1, alignItems:'flex-end', paddingRight:-10}}>
{this.state.selectedStatus?
**<ButtonComponent buttonColor={"black"} buttonTextColor={"white"} fullRounded={true}
borderHighlight={true} buttonWidth={70} buttonHeight={30}
onPress={()=>this.props.showSelected(this.changeSelectStatus(this.props.item.key)) }>
Selected
</ButtonComponent>
:
<ButtonComponent buttonColor={"white"} buttonTextColor={"black"} fullRounded={true}
borderHighlight={true} buttonWidth={70} buttonHeight={30}
onPress={()=>this.props.showSelected(this.changeSelectStatus(this.props.item.key)) }>
Select
</ButtonComponent>
}
</View>
</View>
)
}
}
export default class SelectMembersBody extends Component {
constructor(props){
super(props)
this.state={
selectedButtons:[],
selectAllBtnStatus:false,
}
}
selectAllMembers=()=>{
let allMembers=[];
if(!this.state.selectAllBtnStatus){
membersData.forEach(element => {
if(!this.state.selectedButtons.includes(element.key))
allMembers.push(element.key)
});
this.setState({
selectAllBtnStatus:!this.state.selectAllBtnStatus,
selectedButtons:[...this.state.selectedButtons, allMembers]
})
}
else{
this.setState({
selectAllBtnStatus:!this.state.selectAllBtnStatus,
selectedButtons:[...allMembers]
})
}
}
showSelected=(callback)=>{
let val = callback;
if(!this.state.selectedButtons.includes(val))
this.setState({selectedButtons:[...this.state.selectedButtons, val]});
else{
let newMarkers=[...this.state.selectedButtons]
let index = newMarkers.indexOf(val);
if (index >= 0) {
newMarkers.splice( index, 1 );
}
this.setState({selectedButtons:newMarkers});
}
}
render(){
return(
<View style={{flex:1, }}>
<Text>{this.state.selectedButtons}</Text>
<View>
{this.state.selectAllBtnStatus?
<ButtonComponent buttonColor={"black"} buttonTextColor={"white"} fullRounded={true}
borderHighlight={true} buttonWidth={85} buttonHeight={30} onPress={this.selectAllMembers}>
Selected All
</ButtonComponent>
:
<ButtonComponent buttonColor={"white"} buttonTextColor={"black"} fullRounded={true}
borderHighlight={true} buttonWidth={85} buttonHeight={30} onPress={this.selectAllMembers}>
Select All
</ButtonComponent> }
</View>
<FlatList data={membersData} extraData={this.state}
renderItem={({item, index})=>{
return(
<View>
<FlatListItem item={item} index={index} isSelected={this.state.selectAllBtnStatus} showSelected={this.showSelected} ></FlatListItem>
</View>
)
}
}></FlatList>
</View>
)
}
}
I know that it's quite harder to step into someone's shoes. The code I provided in my question might not be that effective since I'm a learner. That's why it is uncomfortable to get on to the code flow. So, I decided to answer my own question after reading some articles, docs and similar questions on StackOverFlow.
So, my question is why the flatlist was not getting re-rendered on setState. To be more precise, if you've gone through the pictures above, on selecting the Select All button all the buttons in the items should be toggled to selected state.
To make the flatlist re-render, we need to add an additional prop "extraData"
By passing extraData={this.state} to FlatList we make sure FlatList itself will re-render when the state.selected changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.
You can get it's full documentation here.
In my case, I set extraData = {this.state} since the status of buttons in each of the flatlist item depends on the array which is present in the parent component.
So, I've sent it to child component via props.
Now the flatlist is working fine and re-rendering on every state update.
I am making a To Do list app using React Native, where I add events to a FlatList and then have a button that removes that event once it it finished. So far this is what I have. It seems very hacky to me, but most of it works.
import React from 'react';
import { StyleSheet, Text, View, TextInput,TouchableOpacity, FlatList} from 'react-native';
export default class App extends React.Component {
constructor(props){
const data = [];
super(props);
this.state ={
text: 'Enter activity here',
data: data,
color: true,
currNum: 0,
}
}
updateText(){
this.setState({data:this.state.data.concat({key:this.state.text,index:this.state.currNum})});
this.state.currNum++;
}
removeText(item){
this.setState({data:this.state.data.pop(item.index)});
this.state.currNum--;
}
render() {
return (
<View style={styles.container}>
<Text></Text>
<View style = {{flexDirection:'row',justifyContent:'flex-end'}}>
<TextInput style = {{fontSize:30,borderColor:'black', flex:1, marginTop:20}} onChangeText = {(text) => this.setState({text})}value = {this.state.text}/>
<TouchableOpacity style = {{marginTop:20}}onPress = {()=>(this.updateText())}>
<Text>Add to list</Text>
</TouchableOpacity>
</View>
<View style = {{flex:1, flexDirection:'row'}}>
<FlatList
data = {this.state.data}
extraData = {this.state}
renderItem = {({item}) => <View><Text style={styles.text} >{item.key}</Text><TouchableOpacity onPress = {() => this.removeText(item)}><Text>Remove</Text></TouchableOpacity></View>}
/>
</View>
</View>
);
}
}
When I press the "remove" button, I delete an element from the list of data that the FlatList uses. However, whenever I do this I get an error saying "Tried to get frame for out of range index NaN". Is there a way for me to regularly update and remove a FlatList, and to re-render the FlatList once I have removed an item? I have tried using the extraDate prop, but it hasn't worked. I believe I am using it wrong though. Thank you for all the help.
I think you should use .filter
removeText(item){
this.setState({
data: this.state.data.filter((_item)=>_item.key !== item.key)
});
}
And what this.state.currNum - is for?
use this instead you shouldn't mutate this.state and Array.prototype.pop() mutates it
removeText(item, index){
this.setState({data: [
...this.state.data.slice(0, index),
...this.state.data.slice(index + 1)
]});
this.state.currNum--;
}
I am working on a page that basically is supposed to process some back end work and then push on another screen.
This Page should have some text appearing as soon as the page renders that says "submitting your info" then do the backend call, and then the text disappears, and then the whole page performs a push for another screen.
I am confused how to do that !!
This is the render part of the page
render(){
return(
<View style={styles.container}>
<Image style={styles.container} resizeMode="cover" source=
{require('/workingonit.png')}>
<View style={styles.backdropView}>
<Text style={styles.headline}>Submitting your info</Text>
</View>
</Image>
</View>
)
}
I know its something to do with settimeout? or interval?
Sorry I am new to JS and react native .
This example will toggle (hide/show) the text every time you click on the TouchableOpacity by updating the state. You can then, add whatever logic you want as a callback when the state gets updated.
import React from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
export default class DummyPage extends React.Component {
state = {
isTextVisible: false
}
toggleText() {
this.setState({isTextVisible: !this.state.isTextVisible}, () => {
// do some logic here
})
}
renderText() {
if (this.state.isTextVisible) {
return(
<Text>this is a random text</Text>
)
}
}
render() {
return(
<View style={{flex: 1}}>
<TouchableOpacity onPress={this.toggleText}>
<Text>Show Text</Text>
</TouchableOpacity>
{this.renderText()}
</View>
)
}
}
This should work for your API call too. Instead of updating the state with onPress, you can do it when the communication with the backend starts and hide it again when you want to push the user to another screen.
I'm having a problem with a WebView in my React Native app. When no height for the WebView is specified, it defaults to about half the screen height (iPhone 6S). However, when I set a height with the help of Dimensions, it displays fine, but only the original half is interactive – ie. can only scroll using the top half of the screen.
Here are the main parts of my current code:
import React, { Component } from 'react';
import {
...
Dimensions,
...
WebView,
} from 'react-native';
let ScreenHeight = Dimensions.get("window").height;
let ScreenWidth = Dimensions.get("window").width;
class App extends Component {
render() {
return (
<View style={styles.container}>
...
<WebView
source={{uri: 'http://foo.com'}}
style={{height: ScreenHeight, width: ScreenWidth}}
/>
...
</View>
);
}
}
...
const styles = StyleSheet.create({
container: {
backgroundColor: '#bbb',
flex: 1,
},
...
});
AppRegistry.registerComponent('myApp', () => App);
I look forward to any help that can be offered :)
It's possible that an invisible view from your render function is being drawn on the bottom half of the screen.
With out seeing the rest of the render method I couldn't tell, still worth checking.
Thanks for the answers, guys. I've fixed my issue now, and it seems to be such an easy fix. I basically wrapped the WebView in it's own View container. I'm not sure whether it wasn't working because it had sibling elements (ie. NavBar and TabBarIOS – which I left off my previous snippet – sorry!), but the WebView now works great.
Here is my new render function:
render() {
return (
<View style={styles.container}>
<NavBar>
<View>
<WebView
source={{uri: 'http://foo.com'}}
style={{height: ScreenHeight, width: ScreenWidth}}
/>
</View>
<TabBarIOS>
...
</TabBarIOS>
</View>
);
}
Try adding flex style to WebView. Your code will look like this:
<View style={styles.container}>
...
<WebView
source={{uri: 'http://foo.com'}}
style={{flex:1}}
/>
...
</View>