React-native-keyboard-aware-scroll-view: Cannot auto-scroll to TextInput

Created on 3 Apr 2016  ·  20Comments  ·  Source: APSL/react-native-keyboard-aware-scroll-view

I am following the example to try auto-scroll to TextInput in ScrollView, however I got:

image

Any idea where I might go wrong?

question

Most helpful comment

Here you have a nice gif with the above solution @nickmaxwell10

I would love to have a bit of feedback about the scroll docs, because it seems that it's not very clear, so please send some suggestions :+1:

scrl

All 20 comments

+1

The same problem! anyone solved this issue?

+1

Sorry guys, will try to reproduce the error, but I need some piece of code to do that, do you have any?

Hi,
FYI, I have a KeyboardAwareScrollView with 2 TextInput.

According to the following post, you have to tweak the instructions a bit like: https://github.com/APSL/react-native-keyboard-aware-scroll-view/issues/5

  <TextInput ref='foo' onFocus={(event) => {
        this._scrollToInput(event, 'foo');
    }}/>
  _scrollToInput (event, refName) {
    let node = React.findNodeHandle(this.refs[refName]);
    let extraHeight = 70; // height of your text input 
    this.refs.scrollView.scrollToFocusedInput(event, node, extraHeight);
  },

I am getting the same error. +1. Tried @KBLNY's solution above, no luck.

Will try to solve this ASAP, but I’m facing an enormous amount of work, sorry :(

Álvaro Medina Ballester
[email protected]

On 14 Apr 2016, at 09:49, Nick Maxwell [email protected] wrote:

I am getting the same error. +1. Tried @KBLNY https://github.com/KBLNY's solution above, no luck.


You are receiving this because you commented.
Reply to this email directly or view it on GitHub https://github.com/APSL/react-native-keyboard-aware-scroll-view/issues/8#issuecomment-209812516

@nickmaxwell10 Do you have the same issue? You sure you replaced the refs name, function names, etc. with yours? Did you tried from scratch with only one TextInput in your page?

@KBLNY, I have not tried from scratch. Mine is actually quite a complicated use-case. I have multiple ListViews in a ScrollableTabView. I simply tried to replace my ListViews with KeyboardAwareListViews, add in the refs on the text inputs and implement the _scrollToInput function. It crashed on this line this.refs.scrollView.scrollToFocusedInput(event, node, extraHeight); with the "Argument 0 (NSNumber) or RCTUIManager.measureLayout must not be null" error. I'll have to do some re-working on a simpler use-case.

@KBLNY Just tried from a scratch file, still getting the error with the following code on RN 0.23.0

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  Image,
  TextInput,
  View,
} = React;


import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'

var Example = React.createClass({
  getInitialState: function() {
    return {}
  },
  scrollToInput: function(event, reactNode) {
    this.refs.scroll.scrollToFocusedInput(event, reactNode)
  },
  render: function() {
    return (
      <View style={styles.container}>
        <KeyboardAwareScrollView ref='scroll'>
          <View style={{flex:1, }}>
            <TextInput ref='input1' onFocus={this.scrollToInput} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}} />
          </View>
        </KeyboardAwareScrollView>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});

module.exports = Example;

@KBLNY Ok, your fix works... Working demo in RN 0.23.0

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  Image,
  TextInput,
  TouchableHighlight,
  AsyncStorage,
  View,
  AlertIOS,
} = React;


import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'

var Example = React.createClass({
  componentDidMount: function() {
  },
  getInitialState: function() {
    return {}
  },
  scrollToInput: function(event, refName) {
    let node = React.findNodeHandle(this.refs[refName]);
    let extraHeight = 70; // height of your text input 
    this.refs.scrollView.scrollToFocusedInput(event, node, extraHeight);
  },
  render: function() {
    return (
      <View style={styles.container}>
        <KeyboardAwareScrollView ref='scrollView'>
          <View style={styles.textContainer}>
            <TextInput ref='foo' onFocus={(event) => {
                  this.scrollToInput(event, 'foo');
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
          <View style={styles.textContainer}>
            <TextInput ref='foo1' onFocus={(event) => {
                  this.scrollToInput(event, 'foo1');
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
          <View style={styles.textContainer}>
            <TextInput ref='foo2' onFocus={(event) => {
                  this.scrollToInput(event, 'foo2');
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
        </KeyboardAwareScrollView>

      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  textContainer: {
    flex:1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    paddingVertical:100,
  },
});

module.exports = Example;

Ok, it broke when I added multiple scrollviews in a react-native-scrollable-tab-view. Am I doing something wrong here?

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  Image,
  TextInput,
  TouchableHighlight,
  AsyncStorage,
  View,
  AlertIOS,
} = React;


import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'

var ScrollableTabView = require('react-native-scrollable-tab-view');

var Example = React.createClass({
  componentDidMount: function() {
  },
  getInitialState: function() {
    return {}
  },
  scrollToInput: function(event, refName) {
    let node = React.findNodeHandle(this.refs[refName]);
    let extraHeight = 70; // height of your text input 
    var index = this.refs.scrollTabView.state.currentPage;
    this.refs['scrollView_'+index].scrollToFocusedInput(event, node, extraHeight);
  },
  renderScrollViews: function() {
    var views = [];
    var renderRow = this.renderRow;
    for(var i = 0; i < 7; i++) {
      var scrollRef = 'scrollView_'+i;
      views.push(
        <KeyboardAwareScrollView key={scrollRef} ref={scrollRef}>
          <View style={styles.textContainer}>
            <TextInput ref={'foo'+i} onFocus={(event) => {
                  this.scrollToInput(event, 'foo'+i);
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
          <View style={styles.textContainer}>
            <TextInput ref={'foo1'+i} onFocus={(event) => {
                  this.scrollToInput(event, 'foo1'+i);
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
          <View style={styles.textContainer}>
            <TextInput ref={'foo2'+i} onFocus={(event) => {
                  this.scrollToInput(event, 'foo2'+i);
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
        </KeyboardAwareScrollView>
      );
    }
    return views;
  },
  render: function() {
    return (
      <View style={styles.container}>
        <ScrollableTabView ref="scrollTabView" edgeHitWidth={500} >
          {this.renderScrollViews()}
        </ScrollableTabView>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  textContainer: {
    flex:1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    paddingVertical:100,
  },
});

module.exports = Example;

Have you tried to console.log the refs?

For instance,

scrollToInput: function(event, refName) {
  let node = React.findNodeHandle(this.refs[refName]);
  // Check the ref and the node
  console.log('Node', node);
  console.log('refName', refName);
  let extraHeight = 70; // height of your text input 
  var index = this.refs.scrollTabView.state.currentPage;
  // Check your selected tab
  console.log('index', index);
  this.refs['scrollView_'+index].scrollToFocusedInput(event, node, extraHeight);
  // Check also the scroll view index
  console.log('scrollView_', `scrollView_${index}`);
},

Ok, I tried your code but it seems you have a bug somewhere in your refs creation. This is an output of the debugger. You'll see that you're trying to find a node that doesn't exist with ref foo7. Once the React node is null, the error appears.

screen shot 2016-04-15 at 09 45 47

@nickmaxwell10 this code works

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  Image,
  TextInput,
  TouchableHighlight,
  AsyncStorage,
  View,
  AlertIOS,
} = React;


import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'

var ScrollableTabView = require('react-native-scrollable-tab-view');

var Example = React.createClass({
  componentDidMount: function() {
  },
  getInitialState: function() {
    return {}
  },
  scrollToInput: function(event, refName) {
    let node = React.findNodeHandle(this.refs[refName]);
    let extraHeight = 70; // height of your text input
    var index = this.refs.scrollTabView.state.currentPage;
    this.refs['scrollView_'+index].scrollToFocusedInput(event, node, extraHeight);
  },
  renderScrollViews: function() {
    var views = [];
    var renderRow = this.renderRow;
    for(var i = 0; i < 7; i++) {
      var scrollRef = 'scrollView_'+i;
      // Use fixed constants to set the input refs
      const ref1 = `foo${i}`
      const ref2 = `foo1${i}`
      const ref3 = `foo2${i}`
      views.push(
        <KeyboardAwareScrollView key={scrollRef} ref={scrollRef}>
          <View style={styles.textContainer}>
            <TextInput ref={ref1} onFocus={(event) => {
                  this.scrollToInput(event, ref1);
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
          <View style={styles.textContainer}>
            <TextInput ref={ref2} onFocus={(event) => {
                  this.scrollToInput(event, ref2);
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
          <View style={styles.textContainer}>
            <TextInput ref={ref3} onFocus={(event) => {
                  this.scrollToInput(event, ref3);
              }} style={{height: 30, width: 100, borderColor:'#F00', borderWidth:1}}/>
          </View>
        </KeyboardAwareScrollView>
      );
    }
    return views;
  },
  render: function() {
    return (
      <View style={styles.container}>
        <ScrollableTabView ref="scrollTabView" edgeHitWidth={500} >
          {this.renderScrollViews()}
        </ScrollableTabView>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  textContainer: {
    flex:1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    paddingVertical:100,
  },
});

module.exports = Example;

The problem was that once you execute the onFocus event, the i index is beyond bounds so the node can't be found. I've patched your code but please do not take it as an optimum solution.

@allanjsx @ms88privat @xp19870106 please consider posting your code or debugging the findNodeHandle result, because this error is produced once you send null as a node.

Here you have a nice gif with the above solution @nickmaxwell10

I would love to have a bit of feedback about the scroll docs, because it seems that it's not very clear, so please send some suggestions :+1:

scrl

@alvaromb Brilliant! Yes I was setting my refs all wrong. Thanks for clearing this up! Works great!

@alvaromb what method do you use to make those nice gifs? Quicktime screen capture then a mov-> gif converter? Or do you have a tool for this?

I use an app called Licecap

Hi everybody!

Once #22 gets merged, we'll no longer need to do this kind of stuff, the component will autoscroll to the focused TextInput.

Was this page helpful?
0 / 5 - 0 ratings