react-native-smooth-pincode-input
react-native-smooth-pincode-input copied to clipboard
Updating value of the pincode-input
Let's say we need to set a value of pincode-input if the value was received from some source (e.g. in Android - via otp-verify logic).
Getting selection error (4 is codeLength) from the TextInput:
setSpan (4 ... 4) ends beyond length 0
The same problem(
same here
Any solutions to this?
Nope
Use this code
<SmoothPinCodeInput codeLength={6} cellSize={50} cellSpacing={10} textStyle={{ color: 'white', fontSize: FONTSIZE.FONT_25, fontFamily: FONTFAMILY.SEMIBOLD, }} textStyleFocused={{ color: '#ff8b00' }} cellStyle={{ borderBottomWidth: 2, borderColor: 'gray', }} cellStyleFocused={{ borderColor: '#06A8CE', }} placeholder={'*'} value={component.state.code} filledData = {"123734"} onTextChange={code => component.setState({ code })} onFulfill={(code) => component._checkCode(code)} keyboardType={'number-pad'} />
`import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { View, Text, TextInput, StyleSheet, ViewPropTypes, } from 'react-native'; import * as Animatable from 'react-native-animatable';
const styles = StyleSheet.create({ containerDefault: {}, cellDefault: { borderColor: 'gray', borderWidth: 1, }, cellFocusedDefault: { borderColor: 'black', borderWidth: 2, }, textStyleDefault: { color: 'gray', fontSize: 24, }, textStyleFocusedDefault: { color: 'black', }, });
class SmoothPinCodeInput extends Component {
state = { maskDelay: false, focused: false, }; ref = React.createRef(); inputRef = React.createRef();
shake = () => { return this.ref.current.shake(650); };
focus = () => { return this.inputRef.current.focus(); };
blur = () => { return this.inputRef.current.blur(); };
_inputCode = (code) => { const { password, codeLength = 4, onTextChange, onFulfill } = this.props;
if (onTextChange) {
onTextChange(code);
}
if (code.length === codeLength && onFulfill) {
onFulfill(code);
}
// handle password mask
const maskDelay = password &&
code.length - 1 > this.props.value.length; // only when input new char
this.setState({ maskDelay });
if (maskDelay) { // mask password after delay
setTimeout(() => this.setState({ maskDelay: false }), 200);
}
};
_keyPress = (event) => { if (event.nativeEvent.key === 'Backspace') { const { value, onBackspace } = this.props; if (value === '' && onBackspace) { onBackspace(); } } };
_onFocused = (focused) => { this.setState({ focused }); };
render() { const { value, codeLength, cellSize, cellSpacing, placeholder, password, mask, autoFocus, containerStyle, cellStyle, cellStyleFocused, cellStyleFilled, textStyle, textStyleFocused, keyboardType, animationFocused, } = this.props; const { maskDelay, focused } = this.state; return ( <Animatable.View ref={this.ref} style={[{ alignItems: 'stretch', flexDirection: 'row', justifyContent: 'center', position: 'relative', width: cellSize * codeLength + cellSpacing * (codeLength - 1), height: cellSize, }, containerStyle, ]}> <View style={{ position: 'absolute', margin: 0, height: '100%', flexDirection: 'row', alignItems: 'center', }}> {
Array.apply(null, Array(codeLength)).map((_, idx) => {
let value = this.props.filledData
const cellFocused = focused && idx === value.length;
const filled = idx < value.length;
const last = (idx === value.length - 1);
return (
<Animatable.View
key={idx}
style={[
{
width: cellSize,
height: cellSize,
marginLeft: cellSpacing / 2,
marginRight: cellSpacing / 2,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
cellStyle,
cellFocused ? cellStyleFocused : {},
filled ? cellStyleFilled : {},
]}
animation={idx === value.length && focused ? animationFocused : null}
iterationCount="infinite"
duration={500}
>
{(filled || placeholder !== null) && (<Text
style={[
textStyle,
cellFocused ? textStyleFocused : {},
]}>
{filled && (password && (!maskDelay || !last)) ? mask : value.charAt(idx)}
{!filled && placeholder}
</Text>)}
</Animatable.View>
);
})
}
</View>
<TextInput
value={value}
ref={this.inputRef}
onChangeText={this._inputCode}
onKeyPress={this._keyPress}
onFocus={() => this._onFocused(true)}
onBlur={() => this._onFocused(false)}
spellCheck={false}
autoFocus={autoFocus}
keyboardType={keyboardType}
numberOfLines={1}
maxLength={codeLength}
selection={{
start: value.length,
end: value.length,
}}
style={{
flex: 1,
opacity: 0,
textAlign: 'center',
}} />
</Animatable.View>
);
}
static defaultProps = { value: '', filledData : "", codeLength: 4, cellSize: 48, cellSpacing: 4, placeholder: '', password: false, mask: '*', keyboardType: 'numeric', autoFocus: false, containerStyle: styles.containerDefault, cellStyle: styles.cellDefault, cellStyleFocused: styles.cellFocusedDefault, textStyle: styles.textStyleDefault, textStyleFocused: styles.textStyleFocusedDefault, animationFocused: 'pulse', }; }
SmoothPinCodeInput.propTypes = { value: PropTypes.string, filledData: PropTypes.string, codeLength: PropTypes.number, cellSize: PropTypes.number, cellSpacing: PropTypes.number,
placeholder: PropTypes.string, mask: PropTypes.string, password: PropTypes.bool,
autoFocus: PropTypes.bool,
containerStyle: ViewPropTypes.style,
cellStyle: ViewPropTypes.style, cellStyleFocused: ViewPropTypes.style,
textStyle: Text.propTypes.style, textStyleFocused: Text.propTypes.style,
animationFocused: PropTypes.oneOfType([ PropTypes.string, PropTypes.object, ]),
onFulfill: PropTypes.func, onChangeText: PropTypes.func, onBackspace: PropTypes.func,
keyboardType: PropTypes.string, };
export default SmoothPinCodeInput; `
In case somebody stumbles upon this...
This is a react native bug that is likely to be fixed in 0.60. For now I was able to make it work like so: https://gist.github.com/fgreinus/2f62f52a79f98afe43bde5d3b1b6de92
Note: I removed the selection prop in the render method and set the selection prop manually on componentDidUpdate. Really ugly fix, but works for now.
Also, the react native issue for the bug: https://github.com/facebook/react-native/issues/18316
Changing default value from number to string did the trick.