I am writing to create a todo application using react native and firebase, I followed up a youtube to develop an application that saves to file instead of firebase, but read up to include firebase in the application but I don't know how to bind the data to it and ensure until the submit button is clicked before it saves to the data base and display it on the page.
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity
} from 'react-native';
import Note from './Note';
import firebase from 'firebase';
export default class Main extends Component {
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
};
}
componentWillMount() {
var config = {
apiKey: "AIzaSyAB3bO5C7pcLYv745DwwPqUicAshRTdzYk",
authDomain: "mytodo-6b198.firebaseapp.com",
databaseURL: "https://mytodo-6b198.firebaseio.com",
projectId: "mytodo-6b198",
storageBucket: "",
messagingSenderId: "314761285731"
};
firebase.initializeApp(config);
//console.log(firebase);
firebase.database().ref('todo/001').set(
{
note: this.state.noteText,
name: "Tola"
}
).then(() =>{
console.log('inserted');
}).catch((error) =>{
console.log(error);
});
}
render() {
let notes = this.state.noteArray.map((val, key)=>{
return <Note key={key} keyval={key} val={val}
deleteMethod={()=>this.deleteNote(key)}/>
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote.bind(this) } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);
}
addNote(){
if(this.state.noteText){
var d = new Date();
this.state.noteArray.push({
'date':d.getFullYear()+
"/"+(d.getMonth()+1) +
"/"+ d.getDate(),
'note': this.state.noteText
});
this.setState({ noteArray: this.state.noteArray });
this.setState({noteText:''});
}
}
deleteNote(key){
this.state.noteArray.splice(key, 1);
this.setState({noteArray: this.state.noteArray});
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
backgroundColor: '#E91E63',
alignItems: 'center',
justifyContent:'center',
borderBottomWidth: 10,
borderBottomColor: '#ddd'
},
headerText: {
color: 'white',
fontSize: 18,
padding: 26
},
scrollContainer: {
flex: 1,
marginBottom: 100
},
footer: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
zIndex: 10
},
textInput: {
alignSelf: 'stretch',
color: '#fff',
padding: 20,
backgroundColor: '#252525',
borderTopWidth:2,
borderTopColor: '#ededed',
marginBottom: 30
},
addButton: {
position: 'absolute',
zIndex: 11,
right: 20,
bottom: 90,
backgroundColor: '#E91E63',
width: 70,
height: 70,
borderRadius: 35,
alignItems: 'center',
justifyContent: 'center',
elevation: 8
},
addButtonText: {
color: '#fff',
fontSize: 24
}
});
And there is a video tutorial to learn CRUD in native react, firebase and context API. I will be glad to watch one. Thank you
Note.js
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
export default class Note extends Component {
render() {
return (
<View key={this.props.keyval} style={styles.note}>
<Text style={styles.noteText}>{this.props.val.date}</Text>
<Text style={styles.noteText}>{this.props.val.note}</Text>
<TouchableOpacity onPress={this.props.deleteMethod} style={styles.noteDelete}>
<Text style={styles.noteDeleteText}>D</Text>
</TouchableOpacity>
</View>
);
}
}
You need to create the function for creating the payload and saving data. I recommend you to use arrow functions and a promise for asynchronous task. Try this and let me know if it helped you.
import React, {
Component
} from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity
} from 'react-native';
import Note from './Note';
// in the future i would recommend you to use react-native-firebase.
//but for learning purposes it's ok.
import firebase from 'firebase';
export default class Main extends Component {
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
};
}
componentWillMount() {
var config = {
apiKey: "AIzaSyAB3bO5C7pcLYv745DwwPqUicAshRTdzYk",
authDomain: "mytodo-6b198.firebaseapp.com",
databaseURL: "https://mytodo-6b198.firebaseio.com",
projectId: "mytodo-6b198",
storageBucket: "",
messagingSenderId: "314761285731"
};
firebase.initializeApp(config);
// end of componentWillMount
}
// create ALL needed functions
// ist an arrow function
createNote = () => {
//create a promise for waiting until element is succesfully created
return new Promise((resolve, reject) => {
//extract current states
const { noteArray, noteText } = this.state
//create newElement
var d = new Date();
const newElement = {
'date':d.getFullYear()+ "/"+(d.getMonth()+1) + "/"+ d.getDate(),
'note': noteText
}
//set all states
this.setState({
noteArray: [...noteArray, newElement ], //correct array-state manipulation
noteText:''
}, () => resolve(newElement)) //new element ist passed as params to next then
})
}
_addNoteToFirebase = () => {
//this is an arrow function.
//myfunc = (params) => { /*custom logic*/}
const refInDatabase = firebase.database().ref('todo/001');
this.createNote()
.then((elementRecived) => refInDatabase.update(elementRecived))
.then(() => console.log('inserted'))
.catch((error) => console.log(error));
}
deleteNote = (key) => {
const { noteArray } = this.state
this.setState({
noteArray: noteArray.splice(key, 1)
})
}
// here is where render method starts
render() {
let notes = this.state.noteArray.map((val, key)=>{
return <Note
key={key}
keyval={key}
val={val}
deleteMethod={() => deleteNote(key)}
/>
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={this._addNoteToFirebase} style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
backgroundColor: '#E91E63',
alignItems: 'center',
justifyContent:'center',
borderBottomWidth: 10,
borderBottomColor: '#ddd'
},
headerText: {
color: 'white',
fontSize: 18,
padding: 26
},
scrollContainer: {
flex: 1,
marginBottom: 100
},
footer: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
zIndex: 10
},
textInput: {
alignSelf: 'stretch',
color: '#fff',
padding: 20,
backgroundColor: '#252525',
borderTopWidth:2,
borderTopColor: '#ededed',
marginBottom: 30
},
addButton: {
position: 'absolute',
zIndex: 11,
right: 20,
bottom: 90,
backgroundColor: '#E91E63',
width: 70,
height: 70,
borderRadius: 35,
alignItems: 'center',
justifyContent: 'center',
elevation: 8
},
addButtonText: {
color: '#fff',
fontSize: 24
}
});
Related
I am developing a Meals App refering to a React Native - The Practical Guide [2023]
course in Udemy. While using a native route prop i am facin with the mentioned error i.e can't find itemData
Can some help me to figure out where this code is going wrong.
CategoriesScreen.js
import { FlatList, StyleSheet } from "react-native";
import { CATEGORIES } from "../data/dummy-data";
import CategoryGridTile from "../components/CategoryGridTile";
function CategoriesScreen({ navigation }) {
function pressHandler() {
navigation.navigate("Meals Overview", { categoryId: itemData.item.id, });
}
function renderCategoryItem(itemData) {
return (
<CategoryGridTile
title={itemData.item.title}
color={itemData.item.color}
onPress={pressHandler}
/>
);
}
return (
<FlatList
data={CATEGORIES}
keyExtractor={(item) => item.id}
renderItem={renderCategoryItem}
numColumns={2}
/>
);
}
export default CategoriesScreen;
MealsOverviewScreen
import { View,Text,StyleSheet } from "react-native";
import {MEALS} from "../data/dummy-data"
function MealsOverviewScreen({route}){
const catId=route.params.categoryId;
return(
<View style={styles.container}>
<Text>Meals Overview Screen - {catId}</Text>
</View>
)
}
export default MealsOverviewScreen;
const styles=StyleSheet.create(
{
container:{
flex:1,
padding:16,
}
}
)
CategoryGridTile.js
import { Pressable, View, Text, StyleSheet, Platform } from "react-native";
function CategoryGridTile({ title, color,onPress}) {
return (
<View style={styles.gridItem}>
<Pressable
style={({ pressed }) => [styles.buttonStyle,pressed?styles.buttonPressed:null,]}
android_ripple={{ color: "#ccc" }}
onPress={onPress}
>
<View style={[styles.innerContainer,{backgroundColor:color }]}>
<Text style={styles.title}>{title}</Text>
</View>
</Pressable>
</View>
);
}
export default CategoryGridTile;
const styles = StyleSheet.create({
gridItem: {
flex: 1,
margin: 16,
height: 150,
borderRadius: 8,
elevation: 4,
backgroundColor: "white",
shadowColor: "black",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 8,
overflow: Platform.OS == "android" ? "hidden" : "visible",
},
buttonPressed: {
opacity: 0.25,
},
buttonStyle: {
flex: 1,
},
innerContainer: {
flex: 1,
padding: 16,
borderRadius:8,
alignItems: "center",
justifyContent: "center",
},
title: {
fontSize: 18,
fontWeight: "bold",
},
});
Issue is in pressHandler function . There is no itemData variable declared and initialised in function but still you are trying to use it ..
You can change code in CategoriesScreen function created in CategoriesScreen.js as mentioned below
From
function renderCategoryItem(itemData) {
return (
<CategoryGridTile
title={itemData.item.title}
color={itemData.item.color}
onPress={pressHandler}
/>
);
}
To
function renderCategoryItem(itemData) {
return (
<CategoryGridTile
title={itemData.item.title}
color={itemData.item.color}
onPress={()=>{
pressHandler(itemData)
}}
/>
);
}
From
function pressHandler() {
navigation.navigate("Meals Overview", { categoryId: itemData.item.id, });
}
To
function pressHandler(itemData) {
navigation.navigate("Meals Overview", { categoryId: itemData.item.id, });
}
I am creating a react native app on snack expo.
The app allows the user to select image from device on screen one (PhotoSelection.js) and shows the image to screen 2 (FrameSelection.js). Upon selecting an image from device, I am receiving this error:
NoSuchKeyThe specified key does not exist.v2/46/FrameSelectionM0EK0RMAJZ9JH00KGQ3jUVOsp2fXZp3ZWPaMeUjM57WUcEEUGHNvluc/kOn1FcOfRMnlOquUUUZVYGaB/d2cQQNh0Ko=
Screen 1 (PhotoSelection.js):
import React from 'react';
import { StatusBar } from 'expo-status-bar';
import { Text, View, StyleSheet, Image, TouchableOpacity, Button} from 'react-native';
import MyCustomFont from '../assets/Poppins-Bold.ttf';
import { useNavigation } from '#react-navigation/native';
import * as ImagePicker from 'expo-image-picker';
import { Constants } from 'expo-constants';
export const PhotoSelection =() =>{
const handleSelectImage = async () => {
try {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
});
if (!result.cancelled) {
navigation.navigate('FrameSelection', { image: result.uri });
}
} catch (error) {
console.log(error);
}
};
return (
<View style ={styles.container}>
<View>
<Image
style = {styles.img1}
source={require('../assets/image 1.png')}
/>
</View>
<View>
<Image
style = {styles.img2}
source ={require('../assets/Group 546020456.png')}
/>
</View>
<Text style={styles.text}>
Frame your special photos & share it with your friends
</Text>
<TouchableOpacity style ={styles.touchbutton}
onPress={handleSelectImage}
>
SELECT PHOTO
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex:1,
backgroundColor: '#603FC0',
justifyContent: 'center',
alignItems:'center',
width:'100%'
},
img1:{
width:360,
resizeMode:'cover'
},
img2:{
"width":220,
marginTop:50
},
text: {
"width": 200,
"fontFamily": 'MyCustomFont',
"fontStyle": "normal",
"fontWeight": "500",
"fontSize": 16,
"lineHeight": 24,
"textAlign": "center",
},
touchbutton:{
marginTop: 30,
paddingLeft:40,
paddingRight:40,
borderRadius:8,
paddingTop:16,
paddingBottom:16,
alignSelf:'center',
backgroundColor:'white',
fontFamily: 'MyCustomFont',
fontStyle: 'normal',
fontWeight: 700,
fontSize: 16,
},
});
Screen 2 (FrameSelection.js):
import React, {useState} from 'react';
import { Text, View, StyleSheet, Image, TouchableOpacity} from 'react-native';
import {PhotoSelection} from './PhotoSelection';
import { Constants } from 'expo-constants';
export const FrameSelection =({route}) =>{
const frames =
[
{ id: 1, small: require('../assets/image 4.png'), large: require('../assets/image 4.png') },
{ id: 2, small: require('../assets/image 4.png'), large: require('../assets/image 4.png') },
{ id: 3, small: require('../assets/image 4.png'), large: require('../assets/image 4.png') },
];
const [selectedFrame, setSelectedFrame] = useState(frames[0]);
const handleImagePress = (frame) => {
setSelectedFrame(frame);
};
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{route.params.image ? (
<Image source={{ uri: route.params.image }} style={{position: 'absolute', padding:0, top: 0, left: 0, width: '100%', height: '100%', resizeMode: 'contain', backgroundColor: 'white', zIndex: 1} } />
) : (
<Text>No image selected</Text>
)}
<Image
source={selectedFrame.large}
style={{flex:1,position: 'absolute', resizeMode: 'contain', top: 0, left: 0, width: '100%', height: '100%', zIndex: 2}}
resizeMode="contain" />
</View>
<View style={{ flexDirection: 'row', height: 100 }}>
{frames.map((frame) => (
<TouchableOpacity onPress={() => handleImagePress(frame)}>
<Image source={frame.small} style={{ width: 60, height: 60, margin: 10 }} resizeMode="contain" />
</TouchableOpacity>
))}
</View>
</View>
);
};
I Tried checking if the selected image's uri is being passed correctly.
I have been trying to update the email and password value on submitting the form
so that I can pass them in my login API parameters. But I have tried almost everything, the value of this.state won't just update. Every time I try to print the value in console log e.g: cosole.log(this.state.email), it prints empty string i.e the default value set previously.
Here is my code below:
login.js
import React, { Component } from 'react';
import { ThemeProvider, Button } from 'react-native-elements';
import BliszFloatingLabel from './BliszFloatingLabel'
import {
StyleSheet,
Text,
View,
Image,
TextInput,
Animated,
ImageBackground,
Linking
} from 'react-native';
const domain = 'http://1xx.xxx.xx.xxx:8000';
class Login extends Component {
state = {
email: '',
password: '',
}
LoginAPI = (e,p) => {
console.log(e, "####")
}
handleEmail = (text) => {
this.setState({ email: text })
}
handlePassword = (text) => {
this.setState({ password: text })
}
goToSignUpScreen=() =>{
this.props.navigation.navigate('SignUpScreen');
};
goToForgotPasswordScreen=() =>{
this.props.navigation.navigate('ForgotPasswordScreen');
};
render() {
return (
<View style={styles.container} >
<ImageBackground source={require('../bgrndlogin.jpeg')} style={styles.image} >
<View style={styles.heading}>
<Image style={styles.logo} source={require('../loginlogo.png')} />
<Text style={styles.logoText}>Login</Text>
<Text style={styles.logodesc}>Please Login to continue --></Text>
</View>
<View style={styles.form_container}>
<BliszFloatingLabel
label="Email Id"
value={this.state.email}
onChangeText = {this.handleEmail}
onBlur={this.handleBluremail}
/>
<BliszFloatingLabel
label="Password"
value={this.state.password}
onChangeText = {this.handlePassword}
onBlur={this.handleBlurpwd}
secureTextEntry={true}
/>
<ThemeProvider theme={theme}>
<Button buttonStyle={{
opacity: 0.6,
backgroundColor: '#CC2C24',
borderColor: 'white',
borderWidth: 1,
width: 200,
height: 50,
marginTop: 30,
marginLeft: '20%',
alignItems: 'center',
justifyContent: "center"
}}
title="Login"
type="outline"
onPress = {
() => this.LoginAPI(this.state.email, this.state.password)
}
/>
</ThemeProvider>
<Text style={{
marginTop: 70,
color: '#CC2C24',
fontSize: 16,
fontWeight: "bold"
}}
onPress={
this.goToForgotPasswordScreen
}>
Forgot Password?
</Text>
<Text style={{
marginTop: 20,
color: '#CC2C24',
fontSize: 16,
fontWeight: "bold"
}}
onPress={
this.goToSignUpScreen
}>
Don't have an Account?
</Text>
</View>
</ImageBackground>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
logo: {
width: 115,
height: 50,
},
logoText: {
color: 'white',
fontSize: 36,
fontWeight: "bold"
},
logodesc: {
color: '#CC2C24',
fontSize: 18,
fontWeight: "bold"
},
heading: {
flex: 3,
marginLeft:20,
marginTop:30
},
form_container: {
flex: 7,
marginLeft:20,
marginTop:30,
marginRight: 20,
},
image: {
flex: 1,
resizeMode: "cover",
justifyContent: "center"
},
});
const theme = {
Button: {
titleStyle: {
color: 'white',
fontWeight: "bold",
fontSize: 18
},
},
};
export default Login;
I have created a common form as below which I inherit everywhere :
BliszFloatingLabel.js
import React, { Component } from 'react';
import {
Text,
View,
TextInput,
Animated,
} from 'react-native';
class BliszFloatingLabel extends Component {
state = {
entry: '',
isFocused: false,
};
UNSAFE_componentWillMount() {
this._animatedIsFocused = new Animated.Value(0);
}
handleInputChange = (inputName, inputValue) => {
this.setState(state => ({
...state,
[inputName]: inputValue // <-- Put square brackets
}))
}
handleFocus = () => this.setState({ isFocused: true })
handleBlur = () => this.setState({ isFocused: true?this.state.entry!='' :true})
handleValueChange = (entry) => this.setState({ entry });
componentDidUpdate() {
Animated.timing(this._animatedIsFocused, {
toValue: this.state.isFocused ? 1 : 0,
duration: 200,
useNativeDriver: true,
}).start();
}
render() {
// console.log(this.state.entry)
const { label, ...props } = this.props;
const { isFocused } = this.state;
const labelStyle = {
position: 'absolute',
left: 0,
top: !isFocused ? 40 : 0,
fontSize: !isFocused ? 16 : 12,
color: 'white',
};
return (
<View style={{ paddingTop: 20,paddingBottom:20 }}>
<Text style={labelStyle}>
{label}
</Text>
<TextInput
{...props}
style={{
height: 50, fontSize: 16, color: 'white', borderBottomWidth: 1, borderBottomColor: "white"
}}
value={this.state.entry}
onChangeText={this.handleValueChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
blurOnSubmit
/>
</View>
)
}
}
export default BliszFloatingLabel;
Instead of passing onChangeText like this onChangeText={this.handleValueChange} pass in a callback in BliszFloatingLabel and also in Login component.
onChangeText={(text)=>this.handleValueChange(text)}
Snack with the fixture.
https://snack.expo.io/#waheed25/d16fb3
Description
I am working on a react-native project using expo SDK36.
I want to do a swipe left/right list view. I use react-native-swipe-list-view to achieve it.
So far everything worked perfectly, the default example uses a fixed height: 50 per row, while I want to set the height of each row dynamically.
Every attempt where a failure, note that I already use <SwipeListView recalculateHiddenLayout={true} />
This is bad for the UX, since the default line is having a small height: 50, it is nearly impossible to drag the line on iOS and android properly.
Reproduction
Snack: https://snack.expo.io/#kopax/react-native-swipe-list-view-408
import React from 'react';
import { Dimensions, Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import SwipeListView from './components/SwipeListView';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a shareable url.
</Text>
<Card>
<SwipeListView
dimensions={Dimensions.get('window')}
listViewData={Array(20).fill('').map((d, i) => ({
...d,
title: `Item ${i}`,
description: `This is a very long description for item number #${i},
it should be so long that you cannot see all the content,
the issue is about fixing the dynamic height for each row`
}))
}
minHeight={200}
/>
</Card>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
This is my components/SwipeListView.js
import React, { Component } from 'react';
import {
Animated,
Image,
StyleSheet,
TouchableOpacity,
TouchableHighlight,
View,
} from 'react-native';
import {
Avatar,
Button,
Text,
Title,
Subheading,
TouchableRipple,
withTheme,
} from 'react-native-paper';
import { SwipeListView as SwipeListViewDefault } from 'react-native-swipe-list-view';
/* eslint-disable react/prop-types, react/destructuring-assignment, react/no-access-state-in-setstate */
class SwipeListView extends Component {
leftBtnRatio = 0.25;
rightBtnRatio = 0.75;
constructor(props) {
super(props);
this.state = {
listType: 'FlatList',
listViewData: props.listViewData
.map((data, i) => ({ key: `${i}`, ...data })),
};
this.rowTranslateAnimatedValues = {};
props.listViewData
.forEach((data, i) => {
this.rowTranslateAnimatedValues[`${i}`] = new Animated.Value(1);
});
}
getStyles() {
const { minHeight, theme } = this.props;
const { colors } = theme;
return StyleSheet.create({
rowFrontContainer: {
overflow: 'hidden',
},
rowFront: {
alignItems: 'center',
backgroundColor: colors.surface,
borderBottomColor: colors.accent,
borderBottomWidth: 1,
justifyContent: 'center',
minHeight: '100%',
flex: 1,
},
rowBack: {
alignItems: 'center',
backgroundColor: colors.surface,
flexDirection: 'row',
justifyContent: 'space-between',
paddingLeft: 15,
minHeight: '100%',
},
backBtn: {
alignItems: 'center',
bottom: 0,
justifyContent: 'center',
position: 'absolute',
top: 0,
},
backLeftBtn: {
backgroundColor: colors.primary,
left: 0,
width: `${this.leftBtnRatio * 100}%`,
},
backRightBtn: {
backgroundColor: colors.accent,
right: 0,
width: `${this.rightBtnRatio * 100}%`,
},
});
}
onRowDidOpen = (rowKey) => {
console.log('This row opened', rowKey);
};
onSwipeValueChange = swipeData => {
const { dimensions } = this.props;
const { key, value } = swipeData;
if (value < -dimensions.width * this.rightBtnRatio && !this.animationIsRunning) {
this.animationIsRunning = true;
Animated.timing(this.rowTranslateAnimatedValues[key], {
toValue: 0,
duration: 200,
}).start(() => {
const newData = [...this.state.listViewData];
const prevIndex = this.state.listViewData.findIndex(item => item.key === key);
newData.splice(prevIndex, 1);
this.setState({listViewData: newData});
this.animationIsRunning = false;
});
}
};
closeRow(rowMap, rowKey) {
if (rowMap[rowKey]) {
rowMap[rowKey].closeRow();
}
}
deleteRow(rowMap, rowKey) {
this.closeRow(rowMap, rowKey);
const newData = [...this.state.listViewData];
const prevIndex = this.state.listViewData.findIndex(
(item) => item.key === rowKey,
);
newData.splice(prevIndex, 1);
this.setState({ listViewData: newData });
}
render() {
const { minHeight, dimensions, theme } = this.props;
const { colors } = theme;
const styles = this.getStyles();
return (
<SwipeListViewDefault
data={this.state.listViewData}
renderItem={data => (
<Animated.View
style={[styles.rowFrontContainer, {
height: this.rowTranslateAnimatedValues[data.item.key].interpolate({
inputRange: [0, 1],
outputRange: [0, minHeight],
})}]}
>
<TouchableRipple
onPress={() => console.log('You touched me')}
style={styles.rowFront}
underlayColor={colors.background}
>
<View>
<Title>{data.item.title}</Title>
<Text>
{data.item.description}
</Text>
</View>
</TouchableRipple>
</Animated.View>
)}
renderHiddenItem={(data, rowMap) => (
<View style={styles.rowBack}>
<TouchableOpacity
style={[
styles.backLeftBtn,
styles.backBtn,
]}
onPress={() => this.closeRow(rowMap, data.item.key)}
>
<Text>Tap pour annuler</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.backRightBtn,
styles.backBtn,
]}
onPress={() => this.deleteRow(rowMap, data.item.key)}
>
<Animated.View
style={[
styles.trash,
{
transform: [
{
scale: this.rowTranslateAnimatedValues[
data.item.key
].interpolate({
inputRange: [
45,
90,
],
outputRange: [0, 1],
extrapolate:
'clamp',
}),
},
],
},
]}
>
<Text>Swipe left to delete</Text>
</Animated.View>
</TouchableOpacity>
</View>
)}
leftOpenValue={dimensions.width * this.leftBtnRatio}
rightOpenValue={-dimensions.width * this.rightBtnRatio}
previewRowKey={'0'}
previewOpenValue={-40}
previewOpenDelay={3000}
onRowDidOpen={this.onRowDidOpen}
onSwipeValueChange={this.onSwipeValueChange}
recalculateHiddenLayout={true}
/>
);
}
}
export default withTheme(SwipeListView);
Expect
I expect when using recalculateHiddenLayout={true}, to get the hidden row height calculated dynamically
Result Screenshots
On the web, I am able to set the height:
but I when using iOS and Android, the height is forced.
Environment
OS: ios/android/web
RN Version: expo SDK36
How can I set the height of each row dynamically?
Important edit
The problem is the fixed value here in the animation:
height: this.rowTranslateAnimatedValues[data.item.key].interpolate({
inputRange: [0, 1],
outputRange: [0, 200], // <--- here
})}]}
I have replaced it in the example with props.minHeight:
height: this.rowTranslateAnimatedValues[data.item.key].interpolate({
inputRange: [0, 1],
outputRange: [0, this.props.minHeight],
})}]}
It doesn't permit dynamic height, how can I get the row height dynamically?
Not sure where I go about declaring the array with which I want to search from, any assistance would be appreciated. I believe my issue is that I am declaring the "services' array in the incorrect area but I am not sure where else to put it! Or if the commas are the right character to be using in between strings/services
import React, { useState, Component } from 'react';
import { StyleSheet, StatusBar, View, Text, Button, TouchableOpacity } from 'react-native';
import AutoComplete from 'react-native-autocomplete-input';
class CareProviderSequenceScreen extends Component {
constructor (props) {
super (props);
this.state = {
services: [],
query: '',
}
}
render() {
const query = this.state;
const services = {
"Pick up my Prescription",
'Pick up groceries',
'Pick up dry cleaning',
'Pick up my pet',
}
return (
<View style={styles.container}>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
//data to show in suggestion
data={services.length === 1 && comp(query, services[0].title) ? [] : services}
//default value if you want to set something in input
defaultValue={query}
/*onchange of the text changing the state of the query which will trigger
the findFilm method to show the suggestions*/
onChangeText={text => this.setState({ query: text })}
placeholder="Enter your need"
renderItem={({ item }) => (
//you can change the view you want to show in suggestion from here
<TouchableOpacity onPress={() => this.setState({ query: item.title })}>
<Text style={styles.itemText}>
{item.title} ({item.release_date})
</Text>
</TouchableOpacity>
)}
/>
<View style={styles.descriptionContainer}>
{services.length > 0 ? (
<Text style={styles.infoText}>{this.state.query}</Text>
) : (
<Text style={styles.infoText}>Enter The Film Title</Text>
)}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
flex: 1,
padding: 16,
marginTop: 40,
},
autocompleteContainer: {
backgroundColor: '#ffffff',
borderWidth: 0,
},
descriptionContainer: {
flex: 1,
justifyContent: 'center',
},
itemText: {
fontSize: 15,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
},
infoText: {
textAlign: 'center',
fontSize: 16,
},
});
export default CareProviderSequenceScreen ;
CareProviderSequenceScreen .navigationOptions = () => ({
title: "Home & Personal Care",
headerTintColor: '#9EBBD7',
headerStyle: {
height: 65,
backgroundColor: '#1E5797',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.20,
shadowRadius: 1.41,
elevation: 2,}
});
First, you are assigning an object to services array.
Second, you are not accessing the query state properly. It should be
const { query } = this.state