I'm trying to create a passcode protected screen. The screen will uses 4 numeric input as the passcode.
The way I'm doing this is create a TextInput Component and call it 4 times in my main screen.
The problem I'm having is the TextInputs will not focus on the next one as I type the value of the previous TextInput.
I'm using refs for all PasscodeTextInput component (I've been informed that it is a legacy method but I do not know any other way, alas).
Tried this method(without creating my own component), no luck too.
METHOD
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
render() {
const { centerEverything, container, passcodeContainer, textInputStyle} = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={true}
ref="passcode1"
onSubmitEditing={(event) => { this.refs.passcode2.focus() }} />
<PasscodeTextInput
ref="passcode2"
onSubmitEditing={(event) => { this.refs.passcode3.focus() }} />
<PasscodeTextInput
ref="passcode3"
onSubmitEditing={(event) => { this.refs.passcode4.focus() }}/>
<PasscodeTextInput
ref="passcode4" />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
PasscodeTextInput.js
import React from 'react';
import {
View,
Text,
TextInput,
Dimensions
} from 'react-native';
const deviceWidth = require('Dimensions').get('window').width;
const deviceHeight = require('Dimensions').get('window').height;
const PasscodeTextInput = ({ ref, autoFocus, onSubmitEditing, onChangeText, value}) => {
const { inputStyle, underlineStyle } = styles;
return(
<View>
<TextInput
ref={ref}
autoFocus={autoFocus}
onSubmitEditing={onSubmitEditing}
style={[inputStyle]}
maxLength={1}
keyboardType="numeric"
placeholderTextColor="#212121"
secureTextEntry={true}
onChangeText={onChangeText}
value={value}
/>
<View style={underlineStyle} />
</View>
);
}
const styles = {
inputStyle: {
height: 80,
width: 60,
fontSize: 50,
color: '#212121',
fontSize: 40,
padding: 18,
margin: 10,
marginBottom: 0
},
underlineStyle: {
width: 60,
height: 4,
backgroundColor: '#202020',
marginLeft: 10
}
}
export { PasscodeTextInput };
Update 1
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
constructor() {
super()
this.state = {
autoFocus1: true,
autoFocus2: false,
autoFocus3: false,
autoFocus4: false,
}
}
onTextChanged(t) { //callback for immediate state change
if (t == 2) { this.setState({ autoFocus1: false, autoFocus2: true }, () => { console.log(this.state) }) }
if (t == 3) { this.setState({ autoFocus2: false, autoFocus3: true }, () => { console.log(this.state) }) }
if (t == 4) { this.setState({ autoFocus3: false, autoFocus4: true }, () => { console.log(this.state) }) }
}
render() {
const { centerEverything, container, passcodeContainer, testShit, textInputStyle } = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={this.state.autoFocus1}
onChangeText={() => this.onTextChanged(2)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus2}
onChangeText={() => this.onTextChanged(3)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus3}
onChangeText={() => this.onTextChanged(4)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus4} />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
There is a defaultProp for TextInput where one can focus after component mounted.
autoFocus
If true, focuses the input on componentDidMount, the default value is false. for more information please read the related Docs.
UPDATE
After componentDidUpdate it won't work properly. In that case, one can use ref to focus programmatically.
You cannot forward the ref to <TextInput> using that way because ref is one of the special props. Thus, calling this.refs.passcode2 will return you <PasscodeTextInput> instead.
Try change to the following to get the ref from <TextInput>.
PasscodeTextInput.js
const PasscodeTextInput = ({ inputRef, ... }) => {
...
return (
<View>
<TextInput
ref={(r) => { inputRef && inputRef(r) }}
...
/>
</View>
...
);
}
Then, assign the inputRef from <PasscodeTextInput> to a variable and use focus() to switch focus (it is not deprecated as of RN 0.41.2).
index.ios.js
return (
<PasscodeTextInput
autoFocus={true}
onChangeText={(event) => { event && this.passcode2.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode2 = r }}
onChangeText={(event) => { event && this.passcode3.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode3 = r }}
onChangeText={(event) => { event && this.passcode4.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode4 = r }} />
);
P.S: event && this.passcode2.focus() prevents focus is switched when trying to clear the old passcode and enter a new one.
we handled this style of screen with a different approach.
Rather than manage 4 individual TextInputs and handle the navigation of focus across each one (and then back again when the user deletes a character), we have a single TextInput on screen but is invisible (ie. 0px x 0px) wide which has the focus, maxLength and keyboard configuration, etc.
This TextInput takes input from the user but can't actually been seen, as each character is typed in we render the entered text as a series simple View/Text elements, styled much similar to your screen above.
This approach worked well for us with no need to manage what the 'next' or 'previous' TextInput to focus next to.
You can use focus method onChangeText as Jason stated, in addition to that adding maxLength={1} can make you jump to the next input immediately without checking what's added. (just noticed its deprecated, but still this is how I solved my problem, and should do fine until v0.36, and this link explains how you should update the deprecated function).
<TextInput
ref="first"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['second'].focus()
}}
/>
<TextInput
ref="second"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['third'].focus()
}}
/>
...
Please notice that my use of refs are deprecated too, but I've just copied the code since I can guarantee you that was working back then (hopefully works now too).
Finally, the main issue with this type of implementation is, once you try to remove a number with backspace your focus will jump to next one, causing serious UX issues. However, you can listen for backspace key entry and perform something different instead of focusing to next input. So I'll leave a link here for you to further investigate if you choose to use this type of implementation.
Hacky Solution to Previously Described Issue: If you check what's entered in onChangeText prop before doing anything, you can jump to next input if the value is a number, else (that's a backspace), jump back. (Just came up with this idea, I haven't tried it.)
I think the issue is that onSubmitEditing is when you hit the "return" or "enter" key on the regular keyboard... there is not one of those buttons on the keypad.
Assuming you want each input to only have one character, you could look at the onChangeText and then check if text has length 1 and call focus if the length is indeed 1.
<TextInput
ref={input => {
this.nameOrId = input;
}}
/>
<TouchableOpacity
onPress={()=>{
this.nameOrId.focus()
}}
>
<Text>Click</Text>
</TouchableOpacity>
I solve with this code:
const VerifyCode: React.FC = ({ pass, onFinish }) => {
const inputsRef = useRef<Input[] | null[]>([]);
const [active, setActive] = useState<number>(0);
const onKeyPress = ({ nativeEvent }:
NativeSyntheticEvent<TextInputKeyPressEventData>) => {
if (nativeEvent.key === "Backspace") {
if (active !== 0) {
inputsRef.current[active - 1]?.focus();
return setActive(active - 1);
}
} else {
inputsRef.current[active + 1]?.focus();
return setActive(active + 1);
}
return null;
};
return (
<View style={styles.container}>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 0}
ref={(r) => {
inputsRef.current[0] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 1}
ref={(r) => {
inputsRef.current[1] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 2}
ref={(r) => {
inputsRef.current[2] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 3}
ref={(r) => {
inputsRef.current[3] = r;
}}
/>
</View>
);
};
export default VerifyCode;
I put one ref in all the inputs, and when the onKeyPress fire, the function verify if have to go back or go to next input
Solved it by removing autoFocus={true} and setting timeout.
I have a popup as a functional component and using "current.focus()" with Refs like this:
const Popup = ({ placeholder, autoFocus, showStatus, }) => { const inputRef = useRef(null); useEffect(() => {
Platform.OS === 'ios'
? inputRef.current.focus()
: setTimeout(() => inputRef.current.focus(), 40); }, [showStatus]); return (
<View style={styles.inputContainer}>
<TextInput
style={styles.inputText}
defaultValue={placeholder}
ref={inputRef}
/>
</View> };
Related
I am a bit new to react native and I have an issue I need help with
how do I build a text input in react native that has a placeholder that changes to a text view on top when clicked?
Similar to the screenshot below
empty text input field looks like this in its default state
text field with data entered
see the empty input text has a placeholder appearing in the middle of the input text field
see the second diagram, the place holder text is moved to the top of the input field once the user starts typing text into the input field
The easiest way is to use react-native-paper package with their text input:
import * as React from 'react';
import { TextInput } from 'react-native-paper';
const MyComponent = () => {
const [text, setText] = React.useState('');
return (
<TextInput
label="Email"
value={text}
onChangeText={text => setText(text)}
/>
);
};
export default MyComponent;
Result:
Here is what I use without any library, working example and if you want to add animation to the fields working example with animation
import React, { Component } from 'react';
import {
View,
StatusBar,
TextInput,
Text,
} from 'react-native';
class FloatingLabelInput extends Component {
state = {
isFocused: false,
};
handleFocus = () => this.setState({ isFocused: true });
handleBlur = () => this.setState({ isFocused: false });
render() {
const { label, ...props } = this.props;
const { isFocused } = this.state;
const labelStyle = {
position: 'absolute',
left: 0,
top: !isFocused ? 18 : 0,
fontSize: !isFocused ? 20 : 14,
color: !isFocused ? '#aaa' : '#000',
};
return (
<View style={{ paddingTop: 18 }}>
<Text style={labelStyle}>
{label}
</Text>
<TextInput
{...props}
style={{ height: 26, fontSize: 20, color: '#000', borderBottomWidth: 1, borderBottomColor: '#555' }}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
blurOnSubmit
/>
</View>
);
}
}
export default class App extends Component {
state = {
value: '',
};
handleTextChange = (newText) => this.setState({ value: newText });
render() {
return (
<View style={{ flex: 1, padding: 30, backgroundColor: '#f5fcff' }}>
<StatusBar hidden />
<FloatingLabelInput
label="Email"
value={this.state.value}
onChangeText={this.handleTextChange}
/>
</View>
);
}
}
I have created a component called "CommonStyleGenerator", to generate simple style object with keys like height, width and bgColor. I have created a text fields in component and whenever text change in any of text field I am calling onStyleChange with changed field key and it's value to store changed value in parent component.
Here is the CommonStyleGenerator.js component code :
import React, { useEffect, useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';
const CommonStyleGenerator = ({ style = {
height: "100%",
width: "100%",
bgColor: "#ffffff"
}, onStyleChange }) => {
useEffect(() => {
onStyleChange("height", "100%");
onStyleChange("width", "100%");
onStyleChange("bgColor", "#ffffff"); //Only this getting effect.
}, []);
return (
<View>
<TextInput
value={style?.height}
placeholder="height"
onChangeText={(text) => onStyleChange("height", text)}
style={styles.textField}
/>
<TextInput
value={style?.width}
placeholder="width"
onChangeText={(text) => onStyleChange("width", text)}
style={styles.textField}
/>
<TextInput
value={style?.bgColor}
placeholder="background color"
onChangeText={(text) => onStyleChange("bgColor", text)}
style={styles.textField}
/>
</View>
)
}
const styles = StyleSheet.create({
textField: {
borderWidth: 1,
marginVertical: 10
}
})
export default CommonStyleGenerator;
And here is the code of how I called the component in my App.js :
import React, { useEffect, useState } from 'react';
import { View, Button, Text } from 'react-native';
import CommonStyleGenerator from './components/CommonStyleGenerator';
const App = () => {
const [commonStyle, setCommonStyle] = useState(null);
return (
<View style={{flex: 1, alignItems: 'center', padding: 20}}>
<CommonStyleGenerator
style={commonStyle}
onStyleChange={(key, value) => setCommonStyle({
...commonStyle,
[key]: value
})}
/>
<Text>{JSON.stringify(commonStyle, null, 2)}</Text>
</View>
)
}
export default App;
Now, what I want is that on load CommonStyleGenerator component, generate default style if user don't change any textfield. So I called onStyleChange function on useEffect for each key. But for only last key(bgColor) function is called.
Is anyone know how I can solve this issue ?
snack.expo.io link
The commonStyle in state when the three initial onStyleChanges are called is null. Each time it's called, the new state is set with an object with a single key. The synchronous call of an onStyleChange after a previous onStyleChange hasn't updated the commonStyle variable outside yet.
Your current code is like doing:
onStyleChange({ height: '100%' });
onStyleChange({ width: '100%' });
onStyleChange({ bgColor: '#ffffff' });
so only the last object passed appears to be in state on the next render.
Use a callback instead, when setting:
onStyleChange={(key, value) => setCommonStyle(commonStyle => ({
...commonStyle,
[key]: value
}))}
I am currently creating a 4 digit otp (one time password) view for a react native app and i need the TextInput to progressively focus when i type a number on the previous input.
I have been able to make the style change (without focus) but the focus doesn't change with it and when i enter another digit the app crashes.
I want it such that when i type in on the first input, the focus move to the next TextInput and so on and on the last input, it focuses on submit.
How do i go about this?
Below is my code
the component
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, ScrollView, View, Alert, Image } from 'react-native';
import { SimpleLinearGradientButton } from '../../components/Buttons';
import { SimpleCard } from '../../components/Cards';
export default function(props) {
const [otp, setOtp] = useState([]);
const [isFocused, setIsFocused] = useState({ focused: true, index: 0 });
const inputs = Array(4).fill(0);
function renderInputs() {
return inputs.map((input, index) => {
return (
<TextInput
style={
isFocused.focused && index === isFocused.index
? styles.inputFieldsFocused
: styles.inputFields
}
key={index}
keyboardType={'numeric'}
onChange={focus}
></TextInput>
);
});
}
function focus(e) {
setOtp(otp.concat(this.value));
setIsFocused({ focused: true, index: isFocused.index + 1 });
isFocused.index ? e.focus() : null;
}
return (
<ScrollView contentContainerStyle={styles.content}>
<View>
<Image
style={styles.image}
source={require('../../../assets/images/verification.png')}
/>
</View>
<View>
<Text>Verification</Text>
<Text>
Enter the 4 digit sent to your email address
</Text>
</View>
<View>
<SimpleCard>
<>{renderInputs()}</>
</SimpleCard>
<SimpleLinearGradientButton
title="Submit"
/>
</View>
</ScrollView>
);
}
The focus function was meant to focus the next input at that index but this doesn't seem to work but the style changes. How do i go about this? Thanks
I suggest to use single hidden TextInput, and render digits in simple View-s, based on input's value. I see no reason to have different inputs for 4 digit code.
However if you need to use different inputs, you have to control their focus states in imperative way (with refs). See focus() method. Also there are some bugs with this method (https://github.com/facebook/react-native/issues/19366)
See docs here https://facebook.github.io/react-native/docs/textinput
tl;dr Set maxLength of textInput to 1 and on onChangeText callback change to next textInput using refs and focus()
This is a straight-forward implementation to understand easily. You can reduce the code a lot better. And I guess you're supposed to implement Backspace to clear the text and go back to previous textinput. I used onKeyPress prop to achieve that.
import React, { Component } from 'react';
import { Text, View, StyleSheet, TextInput } from 'react-native';
import Constants from 'expo-constants';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
one: '',
two: '',
three: '',
oneFocus: false,
twoFocus: false,
threeFocus: false,
};
}
componentDidMount() {
this.refs.one.focus();
}
handleChangeTextOne = (text) => {
this.setState({ one: text }, () => { if (this.state.one) this.refs.two.focus(); });
}
handleChangeTextTwo = (text) => {
this.setState({ two: text }, () => { if (this.state.two) this.refs.three.focus(); });
}
handleChangeTextThree = (text) => {
this.setState({ three: text });
}
backspace = (id) => {
if (id === 'two') {
if (this.state.two) { this.setState({ two: '' }); } else if (this.state.one) { this.setState({ one: '' }); this.refs.one.focus(); }
} else if (id === 'three') {
if (this.state.three) { this.setState({ three: '' }); } else if (this.state.two) { this.setState({ two: '' }); this.refs.two.focus(); }
}
}
render() {
const { oneFocus, twoFocus, threeFocus } = this.state;
const oneStyle = {
borderBottomColor: oneFocus ? 'red' : 'black',
borderBottomWidth: oneFocus ? 2 : 1,
};
const twoStyle = {
borderBottomColor: twoFocus ? 'red' : 'black',
borderBottomWidth: twoFocus ? 2 : 1,
};
const threeStyle = {
borderBottomColor: threeFocus ? 'red' : 'black',
borderBottomWidth: threeFocus ? 2 : 1,
};
return (
<View style={styles.container}>
<View style={styles.inputcontainer}>
<TextInput
ref='one'
style={[styles.textInput, { ...oneStyle }]}
autoCorrect={false}
autoCapitalize='none'
keyboardType='number-pad'
caretHidden
onFocus={() => this.setState({ oneFocus: true })}
onBlur={() => this.setState({ oneFocus: false })}
maxLength={1}
onChangeText={(text) => { this.handleChangeTextOne(text); }}
value={this.state.one}
/>
<TextInput
ref='two'
onKeyPress={({ nativeEvent }) => (
nativeEvent.key === 'Backspace' ? this.backspace('two') : null
)}
style={[styles.textInput, { ...twoStyle }]}
autoCorrect={false}
autoCapitalize='none'
maxLength={1}
onFocus={() => this.setState({ twoFocus: true })}
onBlur={() => this.setState({ twoFocus: false })}
caretHidden
keyboardType='number-pad'
onChangeText={(text) => { this.handleChangeTextTwo(text); }}
value={this.state.two}
/>
<TextInput
ref='three'
onKeyPress={({ nativeEvent }) => (
nativeEvent.key === 'Backspace' ? this.backspace('three') : null
)}
style={[styles.textInput, { ...threeStyle }]}
autoCorrect={false}
autoCapitalize='none'
onFocus={() => this.setState({ threeFocus: true })}
onBlur={() => this.setState({ threeFocus: false })}
maxLength={1}
caretHidden
keyboardType='number-pad'
onChangeText={(text) => { this.handleChangeTextThree(text); }}
value={this.state.four}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
inputcontainer: {
height: '5%',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
paddingHorizontal: '20%',
marginBottom: '2%',
},
textInput: {
fontSize: 22,
textAlign: 'center',
paddingVertical: 0,
paddingHorizontal: 0,
width: '12%',
},
});
Run this in snack: https://snack.expo.io/#legowtham/otp-textinput-example-react-native
I have a component that has a TextInput and 2 buttons. 1 button increments and the other decrements. I have an onChange and value on the TextInput and when the buttons are clicked the value changes(the text in the input increases or decreases), however typing the value via the TextInput, it doesn't work. It isn't allowing anything to be typed. Backspace won't even work after the increment/decrement buttons are clicked. Thought I'd put my code here to see if anyone could point out what I am missing. I think it has something to do with the .toString() on the value because when I remove that, I am able to type in the TextInput, but I need that .toString() there in order to do numbers and have the initial value as null.
This is the parent component:
measurementValue = (measurement) => {
this.setState({ measurement });
}
updateMeasurement = () => {
this.measurementValue(this.state.measurement);
}
decrement = () => {
this.measurementValue(this.state.measurement - 1);
}
increment = () => {
this.measurementValue(this.state.measurement + 1);
}
render() {
return (
<View>
<MeasurementControl
updateMeasurement={this.updateMeasurement}
decrement={this.decrement}
increment={this.increment}
measurement={this.state.measurement}
/>
</View>
);
}
}
This is the child component:
export class MeasurementControl extends Component {
render() {
const {
updateMeasurement,
decrement,
increment,
measurement,
} = this.props;
const styles = getStyles();
const value = measurement === null
? ''
: measurement;
return (
<View style={styles.container}>
<View style={styles.input}>
<TextInput
style={styles.inputText}
keyboardType='numeric'
placeholder='Enter #'
onChangeText={updateMeasurement}
value={value.toString()}
/>
</View>
<View style={styles.buttonWrapper}>
<Button
buttonStyles={styles.decrementButton}
textStyles={styles.decrementButtonText}
onPress={decrement}
>
__
</Button>
<Button
buttonStyles={styles.incrementButton}
textStyles={styles.buttonText}
onPress={increment}
>
+
</Button>
</View>
</View>
);
}
}
your TextInput have property called onChangeText this event will be triggered each time you write to the input
checkout my code
<TextInput
style={styles.inputText}
keyboardType='numeric'
placeholder='Enter #'
onChangeText={(text) => {
if(text === ""){
updateMeasurement(null);
return;
}
if(isNaN(text)) //this will allow only number
return;
updateMeasurement(parseInt(text))}
}
value={value.toString()}
/>
updateMeasurement = (value) => {
this.measurementValue(value);
}
The part you are missing is to update the value on change
onChangeText={(text) => updateMeasurement(text)}
updateMeasurement = (text) => {
this.measurementValue(text);
}
Hi I am starting to use FlatList component instead of ListView and I am having some problems trying to render the separator, I made a multiple-choice component and it is working ok but I don't understand why it is not rendering the separator from the flatlist, if I put the separator inside the renderItem function it's working ok, but I want to use it from the flatlist as a prop.
One curious thing is if I delete the itemSeparatorComponent prop from the FlatList in render method the component stops updating the checkmark (renderIndicator()) that indicates that item is selected, so it's really annoying this, I put the whole code, please check it.
React native: 0.44.0
import React, { Component } from 'react';
import { Button, Icon, Divider } from 'react-native-elements';
import { FlatList, View, TouchableOpacity, Text } from 'react-native';
import { Card, CardSection } from './commons';
import { appMainColor } from '../constants';
export default class ListOrderItems extends Component {
static navigationOptions = {
title: 'Realice su selección'
};
state = { selected: [], items: this.props.navigation.state.params.items };
onItemPress = (item) => {
const selected = this.state.selected;
const index = selected.indexOf(item.name);
if (index === -1) {
selected.push(item.name);
} else {
selected.splice(index, 1);
}
this.setState({ selected });
};
isSelected = (item) => {
return this.state.selected.indexOf(item.name) !== -1;
};
keyExtractor = (item, index) => {
return index;
};
renderOkButton = () => {
if (this.props.navigation.state.params.type === 'multipleChoice') {
return (
<Button
raised
borderRadius={5}
backgroundColor={appMainColor}
title='Aceptar'
onPress={() => this.props.navigation.goBack()}
/>
);
}
};
renderCancelButton = () => {
return (
<Button
raised
borderRadius={5}
backgroundColor={appMainColor}
title='Cancelar'
onPress={() => this.props.navigation.goBack()}
/>
);
};
renderIndicator = (item) => {
if (this.isSelected(item)) {
return <Icon name="check-circle" color={appMainColor} />;
}
};
renderSeparator = () => {
return <Divider />;
};
renderItem = ({ item, index }) => {
return (
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.onItemPress(item, index)}
>
<View style={styles.row}>
<View style={styles.optionLabel}>
<Text>{item.name} (${item.price})</Text>
</View>
<View style={styles.optionIndicator}>
{this.renderIndicator(item, index)}
</View>
</View>
</TouchableOpacity>
);
};
render() {
return (
<View>
<Card>
<CardSection>
<FlatList
data={this.state.items}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
itemSeparatorComponent={() => this.renderSeparator()}
/>
</CardSection>
</Card>
<Card>
<CardSection style={{ justifyContent: 'space-around' }}>
{this.renderOkButton()}
{this.renderCancelButton()}
</CardSection>
</Card>
</View>
);
}
}
const styles = {
row: {
flexDirection: 'row',
padding: 5
},
optionLabel: {
flex: 1,
},
optionIndicator: {
width: 30,
height: 30,
justifyContent: 'center',
alignItems: 'center'
}
};
I think you made some typo, it should be ItemSeparatorComponent, not itemSeparatorComponent.
Flatlist list items are pure components if you want to check with are selected you should set this in the data source you pass in. Otherwise, the props for the item remain the same and the component will not rerender.
For the divider can you try itemSeparatorComponent={Divider}