@@ -131,9 +131,7 @@ export default class extends Component {
131131 onFocus = { this . _onFocus }
132132 onBlur = { this . _onBlur } { ...otherProps } >
133133 < View style = { { marginBottom : contentBottomOffset } }
134- onStartShouldSetResponderCapture = { isIOS ? this . _onTouchStart : null }
135- onResponderMove = { this . _onTouchMove }
136- onResponderRelease = { this . _onTouchEnd } >
134+ onStartShouldSetResponderCapture = { isIOS ? this . _onTouchStart : null } >
137135 { newChildren }
138136 < View style = { styles . hidden }
139137 pointerEvents = "none" >
@@ -179,7 +177,7 @@ export default class extends Component {
179177 }
180178
181179 _cloneDeepComponents ( Component ) {
182- if ( isArray ( Component ) ) {
180+ if ( Component instanceof Array ) {
183181 return Component . map ( subComponent => this . _cloneDeepComponents ( subComponent ) ) ;
184182 } else if ( Component && Component . props && Component . props . children ) {
185183 const newComponent = { ...Component } ;
@@ -202,8 +200,7 @@ export default class extends Component {
202200
203201 Component . props . onChange = event => {
204202 this . _onChange ( event ) ;
205- onChange &&
206- onChange ( event ) ;
203+ onChange && onChange ( event ) ;
207204 } ;
208205
209206 Component . props . onSelectionChange = event => {
@@ -219,9 +216,11 @@ export default class extends Component {
219216 onSelectionChange ( event ) ;
220217 } ;
221218
222- // 使用防抖函数有两个目的
223- // - 确保 scrollToKeyboardRequest 在 onSelectionChange 之后执行
224- // - 短时间内不会重复执行 onContentSizeChange,因为当一次粘贴进许多行文本时,可能会连续触发多次 onContentSizeChange
219+ /**
220+ * 使用防抖函数有两个目的
221+ * - 确保 scrollToKeyboardRequest 在 onSelectionChange 之后执行
222+ * - 短时间内不会重复执行 onContentSizeChange,因为当一次粘贴进许多行文本时,可能会连续触发多次 onContentSizeChange
223+ */
225224 Component . props . onContentSizeChange = debounce ( event => {
226225 this . _onContentSizeChange ( event ) ;
227226 onContentSizeChange && onContentSizeChange ( event ) ;
@@ -243,10 +242,12 @@ export default class extends Component {
243242 } ) ;
244243 }
245244
246- // 这里必须使用防抖函数
247- // 因为在真机上,当行数增多时,每调整一次 measureInputValue 的值,onContentSizeChange 都会触发多次。
248- // 如果不使用防抖函数,那么在 onContentSizeChange 第一次触发时,measureInputVisible 就会被设置为 false,导致无法获取正确的值。
249- // 但在模拟器上没有这个问题。
245+ /**
246+ * 这里必须使用防抖函数
247+ * 因为在真机上,当行数增多时,每调整一次 measureInputValue 的值,onContentSizeChange 都会触发多次。
248+ * 如果不使用防抖函数,那么在 onContentSizeChange 第一次触发时,measureInputVisible 就会被设置为 false,导致无法获取正确的值。
249+ * 但在模拟器上没有这个问题。
250+ */
250251 _onContentSizeChangeMeasureInput = debounce ( event => {
251252 if ( ! this . _measureCallback ) return ;
252253 this . _measureCallback ( event . nativeEvent . contentSize . height ) ;
@@ -327,6 +328,9 @@ export default class extends Component {
327328 } ;
328329
329330 _onKeyboardShow = ( ) => {
331+ // 在 react-native v0.57 版本中(也可能更早),键盘弹出时,该回调会连续执行3次
332+ // 导致 scrollResponderScrollNativeHandleToKeyboard 工作不正常
333+ if ( this . _keyboardShow ) return ;
330334 this . _keyboardShow = true ;
331335 this . _scrollToKeyboardRequest ( ) ;
332336 } ;
@@ -343,32 +347,36 @@ export default class extends Component {
343347 } ) ;
344348 } ;
345349
346- // 这个方法是为了防止 ScrollView 在滑动结束后触发 TextInput 的 focus 事件
350+ /**
351+ * 这个方法是为了防止 ScrollView 在滑动结束后触发 TextInput 的 focus 事件
352+ */
347353 _onTouchStart = event => {
348354 const target = event . target || event . currentTarget ;
349355 if ( target === this . _curFocus ) return false ;
350356
351357 const targetInst = event . _targetInst ;
352- let uiViewClassName ;
353- uiViewClassName = targetInst . type || // >= react-native 0.49
358+ const uiViewClassName = targetInst . type || // >= react-native 0.49
354359 targetInst . viewConfig . uiViewClassName ; // <= react-native 0.48
355- return uiViewClassName === 'RCTTextField' || uiViewClassName === 'RCTTextView' ;
360+ return uiViewClassName === 'RCTTextField' || uiViewClassName === 'RCTTextView' || uiViewClassName === 'RCTMultilineTextInputView' ;
356361 } ;
357362
358- // 在单行 TextInput 中
359- // onFocus 在 keyboardWillShow 与 keyboardDidShow 之前触发
360- // 在多行 TextInput 中
361- // onFocus 在 keyboardDidShow 之前触发
362- // onFocus 在 keyboardWillShow 之后触发
363+ /**
364+ * 在单行 TextInput 中
365+ * onFocus 在 keyboardWillShow 与 keyboardDidShow 之前触发
366+ * 在多行 TextInput 中
367+ * onFocus 在 keyboardDidShow 之前触发
368+ * onFocus 在 keyboardWillShow 之后触发
369+ */
363370 _onFocus = event => {
371+ const target = event . target || event . currentTarget ;
372+ this . _curFocus = target ;
373+ 364374 // 当 onStartShouldSetResponderCapture 返回 true 时
365375 // 被激活的 TextInput 无法使用 Keyboard.dismiss() 来收起键盘
366376 // TextInput.State.currentlyFocusedField() 也无法获取当前焦点ID
367377 // 原因可能是系统并未判定 TextInput 获取焦点,这可能是一个 bug
368378 // 通常需要在 onStartShouldSetResponderCapture 返回 false 的情况下再点击一次 TextInput 才能恢复正常
369379 // 所以这里手动再设置一次焦点
370- const target = event . target || event . currentTarget ;
371- this . _curFocus = target ;
372380 focus ( target ) ;
373381
374382 const inputInfo = this . _getInputInfo ( target ) ;
@@ -400,21 +408,32 @@ export default class extends Component {
400408 if ( this . _curFocus === target ) this . _curFocus = null ;
401409 }
402410
403- // onChange 在 onContentSizeChange 之前触发
404- // onChange 在 onSelectionChange 之后触发
411+ /**
412+ * onChange 在 onContentSizeChange 之前触发
413+ * onChange 在 onSelectionChange 之后触发
414+ */
405415 _onChange = event => {
406416 const target = event . target || event . currentTarget ;
407417 const inputInfo = this . _getInputInfo ( target ) ;
408418 inputInfo . text = event . nativeEvent . text ;
409419 }
410420
411- // onSelectionChange 在 keyboardDidShow 之前触发
412- // onSelectionChange 在 onContentSizeChange 之前触发
413- // onSelectionChange 在 onFocus 之后触发
414- _onSelectionChange = event => {
421+ /**
422+ * onSelectionChange 在 keyboardDidShow 之前触发
423+ * onSelectionChange 在 onContentSizeChange 之前触发
424+ * onSelectionChange 在 onFocus 之后触发
425+ *
426+ * 在 react-native v0.55 版本中(也可能更早),_onSelectionChange 会连续触发
427+ * 在多行输入框中,如果选中的是非结尾行,那么多次触发时 event.nativeEvent.selection.end 的值可能会变为文本最后一个字符的 index
428+ * 这将导致最终调整位置不正确
429+ * 因此,这里需要使用防抖函数来避开回调连续的执行
430+ */
431+ _onSelectionChange = debounce ( event => {
415432 const target = event . target || event . currentTarget ;
416433 const inputInfo = this . _getInputInfo ( target ) ;
434+ 417435 inputInfo . selectionEnd = event . nativeEvent . selection . end ;
436+ 418437 if ( inputInfo . text === undefined ) {
419438 inputInfo . text = getProps ( event . _targetInst ) . value ;
420439 }
@@ -425,7 +444,7 @@ export default class extends Component {
425444 inputInfo . onFocusRequireScroll = false ;
426445 this . _scrollToKeyboardRequest ( ) ;
427446 }
428- } ;
447+ } , 1 ) ;
429448
430449 _onContentSizeChange = event => {
431450 if ( ! event . nativeEvent ) return ; // Fixed: https://github.com/baijunjie/react-native-input-scroll-view/issues/42
@@ -443,6 +462,8 @@ export default class extends Component {
443462function focus ( targetTag ) {
444463 if ( isIOS ) {
445464 UIManager . focus ( targetTag ) ;
465+ // 在 react-native v0.57 版本中(也可能更早),UIManager.focus 不再有效
466+ TextInput . State && TextInput . State . focusTextInput ( targetTag ) ;
446467 } else {
447468 UIManager . dispatchViewManagerCommand (
448469 targetTag ,
@@ -457,10 +478,6 @@ function getProps(targetNode) {
457478 targetNode . _currentElement . props ; // <= react-native 0.48
458479}
459480
460- function isArray ( arr ) {
461- return Object . prototype . toString . call ( arr ) === '[object Array]' ;
462- }
463- 464481const styles = StyleSheet . create ( {
465482 wrap : {
466483 height : '100%' ,
0 commit comments