UNPKG

react-native-sms-verifycode

Version:

A component for entering a set of SMS verification codes for react-native, Compatible for Android and iOS

453 lines (413 loc) 13.2 kB
/* * @Author: shixiaoquan * @Date: 2018-03-20 17:48:11 * @Last Modified by: Edmond.Shi * @Last Modified time: 2020-05-22 10:07:50 */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Alert, Keyboard, TextInput, TouchableOpacity, AppState, Platform, } from 'react-native'; import CodeView from './component/CodeView'; import styles from './styles'; import { Colors, Constant, getScreenWidth, getCodeArray, Constants, } from './util'; class VerifyCode extends Component { constructor(props) { super(props); const { verifyCodeLength, autoFocus, initialCodes, } = props; const codes = initialCodes.filter((item) => { const str = `${item}`.replace(/ /g, ''); if (str) return true; return false; }); const codeArray = getCodeArray(codes, verifyCodeLength); const reducer = (accumulator, currentValue) => `${accumulator}${currentValue}`; this.state = { text: codes.reduce(reducer), codeArray, coverBGColorList: this.getCoverBGColorList(codeArray, verifyCodeLength), focused: autoFocus, }; // 当前输入的code个数 this.curCodeLength = codes.length; } componentDidMount() { this.keyboardDidShowListener = Keyboard.addListener( 'keyboardDidShow', this.keyboardDidShow.bind(this), ); this.keyboardDidHideListener = Keyboard.addListener( 'keyboardDidHide', this.keyboardDidHide.bind(this), ); AppState.addEventListener('change', this.onAppStateChange); } componentWillUnmount() { this.keyboardDidShowListener.remove(); this.keyboardDidHideListener.remove(); AppState.removeEventListener('change', this.onAppStateChange); if(this.timeout) { clearTimeout(this.timeout); } } onAppStateChange = (nextAppState) => { if (Platform.OS === 'android') { if (nextAppState === 'background') { this.preFocused = this.state.focused; } else if (nextAppState === 'active' && this.preFocused) { this.setState({ focused: true }); } } } onChangeText = (text) => { clearTimeout(this.timeout); const { verifyCodeLength = Constant.verifyCodeLength, onInputChangeText, } = this.props; // console.log('text:', text) const codeLength = text.length; if (codeLength === 0) { const codeArray = getCodeArray([], verifyCodeLength); this.curCodeLength = 0; onInputChangeText && onInputChangeText(text); this.setState({ text: '', codeArray, coverBGColorList: this.getCoverBGColorList(codeArray, verifyCodeLength), }); } else { let codeArray = []; codeArray = text.split(''); // add if (codeLength > this.curCodeLength) { if (isNaN(codeArray[codeLength - 1]) || codeArray[codeLength - 1] === ' ') { // console.log('1 codeArray:', codeArray); codeArray = codeArray.filter(code => !isNaN(code) && code !== ' '); // console.log('2 codeArray:', codeArray) const reducer = (accumulator, currentValue) => `${accumulator}${currentValue}`; const codeText = codeArray.length > 0 ? codeArray.reduce(reducer) : ''; this.showAlert(codeText, codeArray, codeLength); } else { if (codeLength === verifyCodeLength) { if (this.props.onInputCompleted) { this.props.onInputCompleted(text); } } codeArray = getCodeArray(codeArray, verifyCodeLength); this.curCodeLength = codeLength; onInputChangeText && onInputChangeText(text); this.setState( { text, codeArray, coverBGColorList: this.getBeforeCoverBGColorList(codeArray, verifyCodeLength), }, () => { this.timeout = setTimeout( () => this.setState({ codeArray, coverBGColorList: this.getCoverBGColorList(codeArray, verifyCodeLength), }), 500, ); }, ); } } else { // minus codeArray = getCodeArray(codeArray, verifyCodeLength); this.curCodeLength = codeLength; onInputChangeText && onInputChangeText(text); this.setState({ text, codeArray, coverBGColorList: this.getCoverBGColorList(codeArray, verifyCodeLength), }); } } } getBeforeCoverBGColorList = (codeArray, verifyCodeLength) => { const coverBGColorList = []; const count = codeArray.filter(code => code !== '').length; for (let i = 0; i < verifyCodeLength; i += 1) { if (codeArray[i] === '' || i === count - 1) { coverBGColorList.push('transparent'); } else { const { coverColor: color } = this.props; coverBGColorList.push(color); } } return coverBGColorList; } getCoverBGColorList = (codeArray, verifyCodeLength) => { const coverBGColorList = []; for (let i = 0; i < verifyCodeLength; i += 1) { if (codeArray[i] === '') { coverBGColorList.push('transparent'); } else { const { coverColor: color } = this.props; coverBGColorList.push(color); } } return coverBGColorList; } keyboardDidShow() { this.keyboardShow = true; if (this.TextInputFocused) { this.setState({ focused: true }); } // this.setState({ focused: true }); // this.focused = false; } keyboardDidHide() { // this.TextInputFocused = false; this.keyboardShow = false; if (this.state.focused) { this.setState({ focused: false }); } } reset = () => { const { verifyCodeLength = Constant.verifyCodeLength } = this.props; const codeArray = getCodeArray([], verifyCodeLength); this.curCodeLength = 0; this.setState({ text: '', codeArray, coverBGColorList: this.getCoverBGColorList(codeArray, verifyCodeLength), }); } blur = () => { this.textInput.focus(); this.textInput.blur(); this.setState({ focused: false }); } focus = () => { this.textInput.focus(); this.setState({ focused: true }); } showAlert = (text, codeArray, codeLength) => { this.curCodeLength = codeLength - 1; const { verifyCodeLength, warningTitle, warningContent, warningButtonText, } = this.props; Alert.alert( warningTitle, warningContent, [ { text: warningButtonText, onPress: () => { codeArray = getCodeArray(codeArray, verifyCodeLength); this.setState({ text, codeArray, coverBGColorList: this.getCoverBGColorList(codeArray, verifyCodeLength), }); }, }, ], { cancelable: false }, ); } bindRef = (ref) => { this.textInput = ref; }; render() { const { focused } = this.state; const { autoFocus, verifyCodeLength, containerStyle, containerPaddingVertical, containerPaddingTop, containerPaddingBottom, containerPaddingHorizontal, containerPaddingLeft, containerPaddingRight, containerBackgroundColor, codeViewStyle, codeViewWidth, codeViewHeight, codeViewBackgroundColor, codeViewBorderWidth, codeViewBorderColor, codeViewBorderRadius, focusedCodeViewBorderColor, codeStyle, codeFontSize, codeColor, secureTextEntry, } = this.props; let gapWidth = 0; let newCodeViewWidth = 0; if (codeViewWidth) { gapWidth = ( getScreenWidth() - (containerPaddingLeft || containerPaddingHorizontal) - (containerPaddingRight || containerPaddingHorizontal) - (verifyCodeLength * codeViewWidth) ) / (verifyCodeLength - 1); // if (containerPaddingHorizontal) { // } else { // gapWidth = (getScreenWidth() - (verifyCodeLength * codeViewWidth)) / (verifyCodeLength + 1); // } newCodeViewWidth = codeViewWidth; } else { gapWidth = ( getScreenWidth() - (containerPaddingLeft || containerPaddingHorizontal) - (containerPaddingRight || containerPaddingHorizontal) ) / ((3 * verifyCodeLength) - 1); // if (containerPaddingHorizontal) { // } else { // gapWidth = getScreenWidth() / ((3 * verifyCodeLength) + 1); // } newCodeViewWidth = 2 * gapWidth; } return ( <TouchableOpacity style={styles.container} activeOpacity={1} onPressIn={() => { if (!this.keyboardShow) { this.blur(); } }} onPressOut={() => this.focus()} > <TextInput ref={this.bindRef} underlineColorAndroid="transparent" caretHidden onBlur={() => { this.TextInputFocused = false; this.setState({ focused: false }); }} onFocus={() => { this.TextInputFocused = true; }} autoFocus={autoFocus} maxLength={verifyCodeLength} keyboardType="numeric" style={styles.hiddenTextInput} value={this.state.text} onChangeText={(text) => { this.setState({ text }); this.onChangeText(text); // onInputCompleted(text) }} /> <CodeView focused={focused} gapWidth={gapWidth} codeArray={this.state.codeArray} coverBGColorList={this.state.coverBGColorList} verifyCodeLength={verifyCodeLength} containerStyle={containerStyle} containerPaddingVertical={containerPaddingVertical} containerPaddingTop={containerPaddingTop} containerPaddingBottom={containerPaddingBottom} containerPaddingHorizontal={containerPaddingHorizontal} containerPaddingLeft={containerPaddingLeft} containerPaddingRight={containerPaddingRight} containerBackgroundColor={containerBackgroundColor} codeViewStyle={codeViewStyle} codeViewBorderColor={codeViewBorderColor} focusedCodeViewBorderColor={focusedCodeViewBorderColor} codeViewWidth={newCodeViewWidth} codeViewHeight={codeViewHeight} codeViewBorderWidth={codeViewBorderWidth} codeViewBorderRadius={codeViewBorderRadius} codeViewBackgroundColor={codeViewBackgroundColor} codeStyle={codeStyle} codeFontSize={codeFontSize} codeColor={codeColor} secureTextEntry={secureTextEntry} /> </TouchableOpacity> ); } } VerifyCode.propTypes = { autoFocus: PropTypes.bool, verifyCodeLength: PropTypes.number, initialCodes: PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.number, PropTypes.string, ])), containerStyle: PropTypes.oneOfType([PropTypes.object]), containerPaddingVertical: PropTypes.number, containerPaddingTop: PropTypes.number, containerPaddingBottom: PropTypes.number, containerPaddingHorizontal: PropTypes.number, containerPaddingLeft: PropTypes.number, containerPaddingRight: PropTypes.number, containerBackgroundColor: PropTypes.string, codeViewStyle: PropTypes.oneOfType([PropTypes.object]), codeViewBorderColor: PropTypes.string, focusedCodeViewBorderColor: PropTypes.string, codeViewWidth: PropTypes.number, codeViewHeight: PropTypes.number, codeViewBorderWidth: PropTypes.number, codeViewBorderRadius: PropTypes.number, codeViewBackgroundColor: PropTypes.string, codeStyle: PropTypes.oneOfType([PropTypes.object]), codeFontSize: PropTypes.number, codeColor: PropTypes.string, secureTextEntry: PropTypes.bool, coverStyle: PropTypes.oneOfType([PropTypes.object]), coverRadius: PropTypes.number, coverColor: PropTypes.string, onInputCompleted: PropTypes.func, onInputChangeText: PropTypes.func, warningTitle: PropTypes.string, warningContent: PropTypes.string, warningButtonText: PropTypes.string, }; VerifyCode.defaultProps = { autoFocus: Constants.autoFocus, verifyCodeLength: Constants.verifyCodeLength, initialCodes: [], containerStyle: null, containerPaddingVertical: null, containerPaddingTop: null, containerPaddingBottom: null, containerPaddingHorizontal: null, containerPaddingLeft: null, containerPaddingRight: null, containerBackgroundColor: null, codeViewStyle: null, codeViewBorderColor: null, focusedCodeViewBorderColor: Colors.focusedCodeViewBorderColor, codeViewWidth: null, codeViewHeight: null, codeViewBorderWidth: null, codeViewBorderRadius: null, codeViewBackgroundColor: null, codeStyle: null, codeFontSize: Constants.codeFontSize, codeColor: Constants.codeColor, secureTextEntry: false, coverStyle: null, coverRadius: null, coverColor: Colors.coverColor, onInputCompleted: null, onInputChangeText: null, warningTitle: Constants.warningTitle, warningContent: Constants.warningContent, warningButtonText: Constants.warningButtonText, }; export default VerifyCode;