当TextInput具有焦点时,如何从键盘后面自动滑出窗口?

McG*_*McG 88 javascript react-native

我已经看到这个黑客本机应用程序自动滚动窗口,但想知道做反应本机的最佳方法...当一个字段获得焦点并在视图中位于低位时,键盘将掩盖文本字段.您可以在示例UIExplorer的TextInputExample.js视图中看到此问题.有谁有一个很好的解决方案?

She*_*ock 81

2017答案

KeyboardAvoidingView可能是现在最好的方式.在这里查看文档.与Keyboard模块相比,它非常简单,它为开发人员提供了更多控制来执行动画.Spencer Carli他的媒体博客上展示了所有可能的方式.

2015答案

执行此操作的正确方法react-native不需要外部库,利用本机代码,并包含动画.

首先定义一个函数来处理onFocus每个TextInput(或者你想要滚动到的任何其他组件)的事件:

// Scroll a component into view. Just pass the component ref string.
inputFocused (refName) {
  setTimeout(() => {
    let scrollResponder = this.refs.scrollView.getScrollResponder();
    scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
      React.findNodeHandle(this.refs[refName]),
      110, //additionalOffset
      true
    );
  }, 50);
}
Run Code Online (Sandbox Code Playgroud)

然后,在你的渲染函数中:

render () {
  return (
    <ScrollView ref='scrollView'>
        <TextInput ref='username' 
                   onFocus={this.inputFocused.bind(this, 'username')}
    </ScrollView>
  )
}
Run Code Online (Sandbox Code Playgroud)

这使用RCTDeviceEventEmitterfor键盘事件和大小调整,测量组件的位置RCTUIManager.measureLayout,并计算所需的精确滚动运动scrollResponderInputMeasureAndScrollToKeyboard.

您可能想要使用additionalOffset参数,以满足特定UI设计的需要.

  • 在较新的React Native版本中,您需要调用:*从'react-native'导入ReactNative;*在调用之前*ReactNative.findNodeHandle()*否则应用程序将崩溃 (8认同)
  • 现在`import {findNodeHandle}来自'react-native'`http://stackoverflow.com/questions/37626851/undefined-is-not-a-functionreact-findnodehandle (6认同)
  • 这是一个很好的发现,但对我来说这还不够,因为虽然ScrollView将确保TextInput在屏幕上,但ScrollView仍然显示用户无法滚动到的键盘下方的内容.设置ScrollView属性"keyboardDismissMode = on-drag"允许用户关闭键盘,但如果键盘下方没有足够*滚动内容,则体验有点刺耳.如果ScrollView只是因为键盘首先需要滚动,而你禁用了弹跳,那么似乎没有办法解除键盘并显示下面的内容 (5认同)
  • @miracle2k - 我有一个功能,当输入模糊时,即键盘关闭时,它会重置滚动视图位置.也许这对你的情况有帮助吗? (2认同)
  • @Sherlock模糊滚动视图重置功能是什么样的?令人敬畏的解决方案:) (2认同)
  • 这个[博客](http://kpetrovi.ch/2015/09/30/react-native-ios-keyboard-events.html)真的很有帮助 (2认同)
  • @VarunGupta我遇到了同样的事情.增加超时(50到100)对我有用.也许这对你也有用. (2认同)

far*_*yer 26

Facebook 开源 KeyboardAvoidingView反应原生0.29来解决这个问题.可以在此处找到文档和用法示例.

  • 谨防KeyboardAvoidingView,它不容易使用.它并不总是像你期望的那样表现.文档几乎不存在. (32认同)

Joh*_*all 12

我们结合了一些代码形式react-native-keyboard-spacer和@Sherlock中的代码来创建一个KeyboardHandler组件,它可以用TextInput元素包裹任何View.奇迹般有效!:-)

/**
 * Handle resizing enclosed View and scrolling to input
 * Usage:
 *    <KeyboardHandler ref='kh' offset={50}>
 *      <View>
 *        ...
 *        <TextInput ref='username'
 *          onFocus={()=>this.refs.kh.inputFocused(this,'username')}/>
 *        ...
 *      </View>
 *    </KeyboardHandler>
 * 
 *  offset is optional and defaults to 34
 *  Any other specified props will be passed on to ScrollView
 */
'use strict';

var React=require('react-native');
var {
  ScrollView,
  View,
  DeviceEventEmitter,
}=React;


var myprops={ 
  offset:34,
}
var KeyboardHandler=React.createClass({
  propTypes:{
    offset: React.PropTypes.number,
  },
  getDefaultProps(){
    return myprops;
  },
  getInitialState(){
    DeviceEventEmitter.addListener('keyboardDidShow',(frames)=>{
      if (!frames.endCoordinates) return;
      this.setState({keyboardSpace: frames.endCoordinates.height});
    });
    DeviceEventEmitter.addListener('keyboardWillHide',(frames)=>{
      this.setState({keyboardSpace:0});
    });

    this.scrollviewProps={
      automaticallyAdjustContentInsets:true,
      scrollEventThrottle:200,
    };
    // pass on any props we don't own to ScrollView
    Object.keys(this.props).filter((n)=>{return n!='children'})
    .forEach((e)=>{if(!myprops[e])this.scrollviewProps[e]=this.props[e]});

    return {
      keyboardSpace:0,
    };
  },
  render(){
    return (
      <ScrollView ref='scrollView' {...this.scrollviewProps}>
        {this.props.children}
        <View style={{height:this.state.keyboardSpace}}></View>
      </ScrollView>
    );
  },
  inputFocused(_this,refName){
    setTimeout(()=>{
      let scrollResponder=this.refs.scrollView.getScrollResponder();
      scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
        React.findNodeHandle(_this.refs[refName]),
        this.props.offset, //additionalOffset
        true
      );
    }, 50);
  }
}) // KeyboardHandler

module.exports=KeyboardHandler;
Run Code Online (Sandbox Code Playgroud)


bry*_*sgo 10

首先,您需要安装react-native-keyboardevents.

  1. 在XCode中,在项目导航器中,右键单击Libraries➜将文件添加到[您的项目名称]转到node_modules➜coid-native-keyboardevents并添加.xcodeproj文件
  2. 在XCode的项目导航器中,选择您的项目.将keyboardevents项目中的lib*.a添加到项目的构建阶段➜使用库链接二进制文件单击之前在项目导航器中添加的.xcodeproj文件,然后转到"构建设置"选项卡.确保打开"全部"(而不是"基本").寻找标题搜索路径并确保它包含$(SRCROOT)/../ react-native/React和$(SRCROOT)/../../ React - 将两者标记为递归.
  3. 运行你的项目(Cmd + R)

然后回到javascript版本:

您需要导入react-native-keyboardevents.

var KeyboardEvents = require('react-native-keyboardevents');
var KeyboardEventEmitter = KeyboardEvents.Emitter;
Run Code Online (Sandbox Code Playgroud)

然后在您的视图中,为键盘空间添加一些状态,并从侦听键盘事件进行更新.

  getInitialState: function() {
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, (frames) => {
      this.setState({keyboardSpace: frames.end.height});
    });
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, (frames) => {
      this.setState({keyboardSpace: 0});
    });

    return {
      keyboardSpace: 0,
    };
  },
Run Code Online (Sandbox Code Playgroud)

最后,在渲染功能的下方添加一个间隔物,这样当它增加尺寸时,它会让你的东西碰到.

<View style={{height: this.state.keyboardSpace}}></View>
Run Code Online (Sandbox Code Playgroud)

也可以使用动画api,但为了简单起见,我们只需在动画后进行调整.

  • 这个答案不再有效,因为RCTDeviceEventEmitter完成了这项工作. (4认同)
  • react-native@0.11.0-rc现在通过DeviceEventEmitter发送键盘事件(例如"keyboardWillShow"),因此您可以为这些事件注册侦听器.但是,在处理ListView时,我发现在ListView的scrollview上调用scrollTo()效果更好:`this.listView.getScrollResponder().scrollTo(rowID*rowHeight);`当它接收到一个行的TextInput时调用它onFocus活动. (2认同)

ami*_*rfl 7

react-native-keyboard-aware-scroll-view为我解决了这个问题. GitHub上的react-native-keyboard-aware-scroll-view


pom*_*omo 6

试试这个:

import React, {
  DeviceEventEmitter,
  Dimensions
} from 'react-native';
Run Code Online (Sandbox Code Playgroud)

...

getInitialState: function() {
  return {
    visibleHeight: Dimensions.get('window').height
  }
},
Run Code Online (Sandbox Code Playgroud)

...

componentDidMount: function() {
  let self = this;

  DeviceEventEmitter.addListener('keyboardWillShow', function(e: Event) {
    self.keyboardWillShow(e);
  });

  DeviceEventEmitter.addListener('keyboardWillHide', function(e: Event) {
      self.keyboardWillHide(e);
  });
}
Run Code Online (Sandbox Code Playgroud)

...

keyboardWillShow (e) {
  let newSize = Dimensions.get('window').height - e.endCoordinates.height;
  this.setState({visibleHeight: newSize});
},

keyboardWillHide (e) {
  this.setState({visibleHeight: Dimensions.get('window').height});
},
Run Code Online (Sandbox Code Playgroud)

...

render: function() {
  return (<View style={{height: this.state.visibleHeight}}>your view code here...</View>);
}
Run Code Online (Sandbox Code Playgroud)

...

它对我有用.键盘显示时视图基本缩小,隐藏时视图再次变回.