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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29313244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:09:50  来源:igfitidea点击:

How to auto-slide the window out from behind keyboard when TextInput has focus?

javascriptreact-native

提问by McG

I've seen this hack for native apps to auto scroll the window, but wondering best way to do it in React Native... When a <TextInput>field gets focus and is positioned low in the view, the keyboard will cover up the text field.

我已经看到了这个黑客的本地应用程序自动滚动窗口,但不知道最好的方式做到这一点在本地做出反应......当一个<TextInput>领域获得焦点,并在视图位置较低时,键盘会掩盖文本字段。

You can see this issue in example UIExplorer's TextInputExample.jsview.

您可以在示例 UIExplorer 的TextInputExample.js视图中看到此问题。

Does anyone have a good solution?

有没有人有好的解决方案?

回答by Sherlock

2017 Answer

2017 答案

The KeyboardAvoidingViewis probably the best way to go now. Check out the docs here. It is really simple compared to Keyboardmodule which gives Developer more control to perform animations. Spencer Carlidemonstrated all the possible ways on his medium blog.

KeyboardAvoidingView可能是现在最好的方法。在此处查看文档。与Keyboard模块相比,它非常简单,它使开发人员可以更好地控制执行动画。Spencer Carli他的媒体博客上展示了所有可能的方法。

2015 Answer

2015 答案

The correct way to do this in react-nativedoes not require external libraries, takes advantage of native code, and includes animations.

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

First define a function that will handle the onFocusevent for each TextInput(or any other component you would like to scroll to):

首先定义一个函数来处理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);
}

Then, in your render function:

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

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

This uses the RCTDeviceEventEmitterfor keyboard events and sizing, measures the position of the component using RCTUIManager.measureLayout, and calculates the exact scroll movement required in scrollResponderInputMeasureAndScrollToKeyboard.

这使用RCTDeviceEventEmitterfor 键盘事件和大小调整,使用 测量组件的位置RCTUIManager.measureLayout,并计算scrollResponderInputMeasureAndScrollToKeyboard.

You may want to play around with the additionalOffsetparameter, to fit the needs of your specific UI design.

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

回答by farwayer

Facebook open sourcedKeyboardAvoidingViewin react native 0.29 to solve this problem. Documentation and usage example can be found here.

Facebook在 react native 0.29 中开源KeyboardAvoidingView来解决这个问题。文档和使用示例可以在这里找到。

回答by John kendall

We combined some of the code form react-native-keyboard-spacer and the code from @Sherlock to create a KeyboardHandler component that can be wrapped around any View with TextInput elements. Works like a charm! :-)

我们结合了 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;

回答by brysgo

First you need to install react-native-keyboardevents.

首先你需要安装react-native-keyboardevents

  1. In XCode, in the project navigator, right click Libraries ? Add Files to [your project's name] Go to node_modules ? react-native-keyboardevents and add the .xcodeproj file
  2. In XCode, in the project navigator, select your project. Add the lib*.a from the keyboardevents project to your project's Build Phases ? Link Binary With Libraries Click .xcodeproj file you added before in the project navigator and go the Build Settings tab. Make sure 'All' is toggled on (instead of 'Basic'). Look for Header Search Paths and make sure it contains both $(SRCROOT)/../react-native/React and $(SRCROOT)/../../React - mark both as recursive.
  3. Run your project (Cmd+R)
  1. 在 XCode 中,在项目导航器中,右键单击 Libraries ? 将文件添加到 [您的项目名称] 转到 node_modules ?react-native-keyboardevents 并添加 .xcodeproj 文件
  2. 在 XCode 的项目导航器中,选择您的项目。将 keyboardevents 项目中的 lib*.a 添加到项目的 Build Phases 中?Link Binary With Libraries 单击您之前在项目导航器中添加的 .xcodeproj 文件,然后转到 Build Settings 选项卡。确保打开“全部”(而不是“基本”)。查找 Header Search Paths 并确保它包含 $(SRCROOT)/../react-native/React 和 $(SRCROOT)/../../React - 将两者标记为递归。
  3. 运行你的项目 (Cmd+R)

Then back in javascript land:

然后回到 javascript 领域:

You need to import the react-native-keyboardevents.

您需要导入 react-native-keyboardevents。

var KeyboardEvents = require('react-native-keyboardevents');
var KeyboardEventEmitter = KeyboardEvents.Emitter;

Then in your view, add some state for the keyboard space and update from listening to the keyboard events.

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

  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,
    };
  },

Finally, add a spacer to your render function beneath everything so when it increases size it bumps your stuff up.

最后,在你的渲染函数下面添加一个垫片,这样当它增加尺寸时,它就会把你的东西弄起来。

<View style={{height: this.state.keyboardSpace}}></View>

It is also possible to use the animation api, but for simplicity's sake we just adjust after the animation.

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

回答by amirfl

react-native-keyboard-aware-scroll-view solved the problem for me. react-native-keyboard-aware-scroll-view on GitHub

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

回答by pomo

Try this:

尝试这个:

import React, {
  DeviceEventEmitter,
  Dimensions
} from 'react-native';

...

...

getInitialState: function() {
  return {
    visibleHeight: Dimensions.get('window').height
  }
},

...

...

componentDidMount: function() {
  let self = this;

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

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

...

...

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

keyboardWillHide (e) {
  this.setState({visibleHeight: Dimensions.get('window').height});
},

...

...

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

...

...

It worked for me. The view basically shrinks when the keyboard is displayed, and grows back again when its hidden.

它对我有用。显示键盘时,视图基本上会缩小,而在隐藏时会再次变长。

回答by Aakash Sigdel

Just wanted to mention, now there is a KeyboardAvoidingViewin RN. Just import it and use it as any other module in RN.

只是想提一下,现在有一个KeyboardAvoidingView在RN。只需导入它并将其用作 RN 中的任何其他模块。

Here is the link to the commit on RN:

这是 RN 提交的链接:

https://github.com/facebook/react-native/commit/8b78846a9501ef9c5ce9d1e18ee104bfae76af2e

https://github.com/facebook/react-native/commit/8b78846a9501ef9c5ce9d1e1​​8ee104bfae76af2e

It is available from 0.29.0

从 0.29.0 开始可用

They have also included an example on UIExplorer.

他们还包括一个关于 UIExplorer 的示例。

回答by Adrian Zghibarta

Maybe is to late, but the best solution is to use a native library, IQKeyboardManager

也许为时已晚,但最好的解决方案是使用本机库IQKeyboardManager

Just drag and drop IQKeyboardManager directory from demo project to your iOS project. That's it. Also you can setup some valus, as isToolbar enabled, or the space between text input and keyboard in the AppDelegate.m file. More details about customisation are in the GitHub page link that I've added.

只需将 IQKeyboardManager 目录从演示项目拖放到您的 iOS 项目。就是这样。您还可以设置一些值,如启用 isToolbar,或 AppDelegate.m 文件中文本输入和键盘之间的空间。有关自定义的更多详细信息,请参见我添加的 GitHub 页面链接。

回答by Nath

You can combine a few of the methods into something a little simpler.

您可以将一些方法组合成更简单的方法。

Attach a onFocus listener on your inputs

在您的输入上附加一个 onFocus 侦听器

<TextInput ref="password" secureTextEntry={true} 
           onFocus={this.scrolldown.bind(this,'password')}
/>

Our scroll down method looks something like :

我们的向下滚动方法看起来像:

scrolldown(ref) {
    const self = this;
    this.refs[ref].measure((ox, oy, width, height, px, py) => {
        self.refs.scrollView.scrollTo({y: oy - 200});
    });
}

This tells our scroll view (remember to add a ref) to scroll to down to the position of our focused input - 200 (it's roughly the size of the keyboard)

这告诉我们的滚动视图(记得添加一个引用)向下滚动到我们聚焦输入的位置 - 200(它大约是键盘的大小)

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

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

keyboardDidHide(e) {
    this.refs.scrollView.scrollTo({y: 0});
}

Here we reset our scroll view back to the top,

在这里,我们将滚动视图重置回顶部,

enter image description here

在此处输入图片说明

回答by deanmcpherson

@Stephen

@斯蒂芬

If you don't mind not having the height animate at exactly the same rate that the keyboard appears, you can just use LayoutAnimation, so that at least the height doesn't jump into place. e.g.

如果您不介意高度动画的速度与键盘出现的速度不完全相同,您可以只使用 LayoutAnimation,这样至少高度不会跳到位。例如

import LayoutAnimation from react-native and add the following methods to your component.

从 react-native 导入 LayoutAnimation 并将以下方法添加到您的组件中。

getInitialState: function() {
    return {keyboardSpace: 0};
  },
   updateKeyboardSpace: function(frames) {
    LayoutAnimation.configureNext(animations.layout.spring);
    this.setState({keyboardSpace: frames.end.height});
  },

  resetKeyboardSpace: function() {
    LayoutAnimation.configureNext(animations.layout.spring);
    this.setState({keyboardSpace: 0});
  },

  componentDidMount: function() {
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  },

  componentWillUnmount: function() {
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace);
    KeyboardEventEmitter.off(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace);
  },

Some example animations are (I'm using the spring one above):

一些示例动画是(我正在使用上面的弹簧):

var animations = {
  layout: {
    spring: {
      duration: 400,
      create: {
        duration: 300,
        type: LayoutAnimation.Types.easeInEaseOut,
        property: LayoutAnimation.Properties.opacity,
      },
      update: {
        type: LayoutAnimation.Types.spring,
        springDamping: 400,
      },
    },
    easeInEaseOut: {
      duration: 400,
      create: {
        type: LayoutAnimation.Types.easeInEaseOut,
        property: LayoutAnimation.Properties.scaleXY,
      },
      update: {
        type: LayoutAnimation.Types.easeInEaseOut,
      },
    },
  },
};

UPDATE:

更新:

See @sherlock's answer below, as of react-native 0.11 the keyboard resizing can be solved using built in functionality.

请参阅下面的@sherlock 的回答,从 react-native 0.11 开始,可以使用内置功能解决键盘大小调整问题。