2017-09-01 10 views
0

画面上の前のtextInputにカーソルのフォーカスを移動したいと思います。 onkeyPressは機能していないのは、その機能がAndroid用ではないIOSプラットフォーム専用であるためです。だから私はAndroidプラットフォームでこのメソッドを防ぐことができますか?Previous TextInput autoFocus on backspace press反応ネイティブのandroid

のTextInputのコード例:

  <TextInput style = {styles.input} 
      keyboardType='numeric' 
      maxLength={1} 
      ref="otpcode1" 
      onChangeText={(event) => { 
       this.setState({otp1: event}); 
       this.refs.otpcode2.focus() }} 
      underlineColorAndroid='#fff'/> 

      <TextInput style = {styles.input} 
      keyboardType='numeric' 
      maxLength={1} 
      ref="otpcode2" 
      onChangeText={(event) => { 
       this.setState({otp2: event}); 
       this.refs.otpcode3.focus() }} 
      underlineColorAndroid='#fff'/> 

      <TextInput style = {styles.input} 
      keyboardType='numeric' 
      maxLength={1} 
      ref="otpcode3" 
      onChangeText={(event) => { 
       this.setState({otp3: event}); 
       this.refs.otpcode4.focus() }} 
      underlineColorAndroid='#fff'/> 

     <TextInput style = {styles.input} 
      keyboardType='numeric' 
      maxLength={1} 
      ref="otpcode4" 
      onChangeText={(event) => { 
       this.setState({otp4: event}); 
       console.log(this.state) }} 
      underlineColorAndroid='#fff'/> 

TextInput view screen example

+0

が、それは他のテキスト入力に戻って行くのですか?バックスペースで? –

+0

はい@Kyle、空のtextInputでbackspaceを押すと、前のtextInputにリダイレクトされます。最後のtextInputが空で、そのフィールドにフォーカスを当てていた画面で、その位置からバックスペースを押すと、フォーカスが2番目の最後のtextInputに表示される必要があります。 –

答えて

0

は、同じ問題を抱えている汚れたソリューションを作ったが、それは動作します。
論理と問題の説明はコードです。

用法:

import {Alert} from 'react-native'; 

onPinEntered = (pin) => { 
    Alert.alert(
     'Entered pin', 
     pin, 
     [{text: 'OK'}] 
    ) 
} 

render() { 
    return (
     <PinInput onPinEntered={this.onPinEntered}/> 
    ) 
} 

コンポーネント:どのような条件で

import React, {PureComponent} from 'react'; 
import { 
    Platform, 
    StyleSheet, 
    TextInput, 
    View, 
    Text, 
    TouchableWithoutFeedback, 
    Keyboard, 
    Animated 
} from 'react-native'; 
import PropTypes from 'prop-types'; 
// import ui_size from '../tools/UISizer'; 

let ui_size = function(points){ 
    //simple sizing function (it project it handles complex screen adaptation) 
    return points*2 
} 

//Main technical problems: 
//1. At date of development RN doesn't provide onKeyPress for android platform 
//2. Changing text and selection of TextInput at same time is extremely buggy 
//Solution: 
//Create TextInput with maxLength = 2 and always prefilled with empty_character = ' ', (value={empty_character}) 
//add self-written cursor pointer 
//track changes of text, if new text is '', backspace was pressed - move cursor to left by 1 
//      if new text is not empty, add new character to buffer (state.pin), mover cursor to right by 1 
//Some times during reloads, selection is setting before defaultValue of TextInput and raises setSpan error (at least on Android) 
//  so additionally track focused state (in render this.input.isFocused() raises strange error: 
//           "TypeError owner.getName is not a function") 
//On android, when input is focused and user hides keyboard by back button, it can only be shown by tap on input 
//     (.focus() don't show keyboard if input is already focused), so track it and blur the input 

const empty_character = ' ' 

export default class PinInput extends PureComponent { 

    static defaultProps = { 
     maxChars: 4, 
     inputProps: {}, 
    }; 

    static propTypes = { 
     maxChars: PropTypes.number, 
     onPinEntered: PropTypes.func, 
     inputProps: PropTypes.object, 
    }; 

    constructor(props) { 
     super(props); 
     this.state = { 
      pin: '', // entered pin 
      selection: undefined, // cursor position 
      isFocused: false, 
      blinkAnim: new Animated.Value(1), 
      isLastCharUpdated: false, // track if last character was updated 
     } 
    } 

    onPressCell = (event, id) => { 
     let {pin} = this.state 
     // by pressing on unfilled cell, set cursor next to last filled cell 
     if (id > pin.length) { 
      id = pin.length 
     } 
     // set cursor position 
     this.setState({ 
      selection: id, 
     }) 
     this.input.focus() 
    } 

    cycleBlinkAnimation =() => { 
     Animated.sequence([ 
      Animated.timing(this.state.blinkAnim, { 
       toValue: 0, 
       duration: 1000 
      }), 
      Animated.timing(this.state.blinkAnim, { 
       toValue: 1, 
       duration: 50 
      }), 
      Animated.timing(this.state.blinkAnim, { 
       toValue: 1, 
       duration: 300 
      }) 
     ]).start((event) => { 
      if (event.finished && this.state.isFocused) { 
       this.cycleBlinkAnimation() 
      } 
     }) 
    } 

    onFocus = (event) => { 
     console.log('onFocus') 
     let {selection} = this.state 
     // update cursor position only if it wasn't setted up 
     if (selection === undefined) { 
      selection = 0 
     } 

     this.setState({ 
      selection, 
      isFocused: true, 
     }) 
    } 

    onBlur = (event) => { 
     console.log('onBlur') 
     this.setState({ 
      selection: undefined, 
      isFocused: false, 
      isLastCharUpdated: false, 
     }) 
    } 

    componentWillUpdate(nextProps, nextState) { 
     if (this.state.isFocused && !nextState.isFocused) { 
      this.state.blinkAnim.stopAnimation() 
     } 
     //restart animation on focus or when cursor moved 
     if ((this.state.selection !== nextState.selection || !this.state.isFocused) && nextState.isFocused) { 
      this.state.blinkAnim.stopAnimation(() => { 
       this.state.blinkAnim.setValue(1) 
       this.cycleBlinkAnimation() 
      }) 
     } 
    } 

    componentDidUpdate(prevProps, prevState) { 
     if (this.state.isFocused 
      && this.state.pin.length === this.props.maxChars // input is full 
      && this.state.selection+1 === this.props.maxChars // cursor is in last cell 
      // && prevState.pin[3] !== this.state.pin[3]) { // last cell was changed 
      && this.state.isLastCharUpdated) { 
      console.log('blur componentDidUpdate') 
      this.input.blur() 
      setTimeout(this.onPinEntered, 1) // dirty hack, on ios sync call onPinEntered prevents blur 
     } 
    } 

    componentWillMount() { 
     this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide); 
    } 

    componentDidMount() { 
     this.cycleBlinkAnimation() 
    } 

    componentWillUnmount() { 
     this.keyboardDidHideListener.remove() 
    } 

    keyboardDidHide =() => { 
     // see reason in top 
     // to prevent unfocussing in IOS simulator with connected hardware keyboard uncomment the following line 
     // or disconnect hardware keyboard by unchecking simulator > Hardware > Keyboard > Connect Hardware Keyboard 
     // if (Platform.OS === 'ios') return; 
     if (this.state.isFocused) { 
      this.input.blur() 
     } 
    } 

    onChangeText = (text) => { 
     let {pin, selection} = this.state 
     text = text.replace(empty_character, '') //remove first occurrence of empty_character 
     let str_replaceAt = function (string, index, replacement) { 
      return string.substr(0, index) + replacement + string.substr(index + 1); 
     } 
     let isLastCharUpdated = false 
     if (text.length === 0) { //backspace 
      pin = str_replaceAt(pin, selection, '') 
      selection -= 1 
      selection = Math.max(selection, 0) 
     } else { //character entered 
      pin = str_replaceAt(pin, selection, text) 
      selection += 1 
      if (selection >= this.props.maxChars) { 
       isLastCharUpdated = true 
      } 
      selection = Math.min(selection, this.props.maxChars - 1) 
     } 
     this.setState({pin, selection, isLastCharUpdated}) 
    } 

    onPinEntered =() => { 
     if ('function' === typeof this.props.onPinEntered) { 
      this.props.onPinEntered(this.state.pin) 
     } 
    } 

    render_cell(id, value, is_active) { 
     let style = (is_active) ? [styles.cell, styles.active_cell] : styles.cell 
     let animation_style = 
      [styles.cursor, { 
       opacity: this.state.blinkAnim,   // Bind opacity to animated value 
      }] 
     return (
      <TouchableWithoutFeedback key={id} onPress={(event) => this.onPressCell(event, id)}> 
       <View> 
        <Text style={style}>{value}</Text> 
        { is_active && <Animated.View style={animation_style} />} 
       </View> 
      </TouchableWithoutFeedback> 
     ) 
    } 

    render() { 
     let inputs = [] 
     let {pin, selection} = this.state 

     //render cells 
     for (let i = 0; i < this.props.maxChars; i++) { 
      inputs.push(this.render_cell(i, pin[i], (selection === i))) 
     } 

     // place cursor after empty_character 
     let input_selection = undefined 
     // as described in top: Some times during reloads, selection is setting before defaultValue ... 
     if (this.input !== undefined && this.state.isFocused) { 
      // so set selection after first character (empty_character) only when input is focused 
      input_selection = {start: 1, end: 1} 
     } 

     let root_style = [this.props.style || {}, styles.root] 

     return (
      <View style={root_style}> 
       <TextInput 
          style={styles.actual_input} 
          ref={(input) => this.input = input} 
          maxLength={2} 
          selection={input_selection} 
          onChangeText={this.onChangeText} 
          autoComplete={false} 
          autoCorrect={false} 
          defaultValue={empty_character} 
          value={empty_character} 
          onFocus={this.onFocus} 
          onBlur={this.onBlur} 
          onSubmitEditing={this.onPinEntered} 
          {...this.props.inputProps} 
       /> 
       <View style={styles.cells_wrapper}> 
        {inputs} 
       </View> 
      </View> 
     ) 
    } 
} 

const styles = StyleSheet.create({ 
    root: {}, 
    actual_input: { 
     position: 'absolute', 
     display: 'none', 
    }, 
    cells_wrapper: { 
     flexDirection: 'row', 
    }, 
    cell: { 
     height: ui_size(24.8), 
     width: ui_size(19.2), 
     textAlign: 'center', 
     elevation: 10, 
     fontSize: ui_size(18), 
     lineHeight: ui_size(24), 
     backgroundColor: 'white', 
     color: 'black', 
     fontWeight: 'bold', 
     paddingHorizontal: ui_size(3), 
     margin: ui_size(6.7)/2, 
     borderRadius: ui_size(2.5), 
     borderBottomColor: 'transparent', 
     zIndex: 1, 
     overflow: 'hidden', // crop corners in IOS 
    }, 
    active_cell: { 
     color: 'rgba(0,0,0,0.4)', 
    }, 
    cursor: { 
     position: 'absolute', 
     height: 1, 
     width: '50%', 
     left: '25%', 
     bottom: 12, 
     borderBottomColor: 'rgba(0,0,0,0.5)', 
     borderBottomWidth: 1, 
     zIndex: 2, 
     elevation: 10, 
    } 
}); 
+0

私はこの問題を、隠されたtextInputを作成することによって解決しました。隠し入力を使用して入力を処理し、通常のテキストとスタイルを使用して数字を表示するだけです。それは4つの異なるテキスト入力を扱うよりも簡単です –

+0

実際には、1つの隠しテキスト入力を使用しました。 onChangeTextを使った不思議な操作は、現在の文字を上書きする機能を提供することです。 –

関連する問題