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

IT技术 javascript react-native
2021-01-29 23:53:23

我已经看到了本机应用程序自动滚动窗口的这种 hack,但想知道在 React Native 中做到这一点的最佳方法......当一个<TextInput>字段获得焦点并在视图中位于较低的位置时,键盘将覆盖文本字段。

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

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

6个回答

2017 答案

KeyboardAvoidingView可能是现在最好的方法。此处查看文档Keyboardmodule相比,它非常简单,它使开发人员可以更好地控制执行动画。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);
}

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

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

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

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

这是一个不错的发现,但对我来说这还不够,因为虽然 ScrollView 将确保 TextInput 在屏幕上,但 ScrollView 仍在键盘下方显示用户无法滚动到的内容。设置 ScrollView 属性 "keyboardDismissMode=on-drag" 允许用户关闭键盘,但如果键盘下方没有足够的滚动内容,体验有点刺耳。如果 ScrollView 只需要首先因为键盘而滚动,并且您禁用了弹跳,那么似乎无法关闭键盘并显示下面的内容
2021-03-13 23:53:23
现在import {findNodeHandle} from 'react-native' stackoverflow.com/questions/37626851/...
2021-03-15 23:53:23
在较新的 React Native 版本中,您需要调用: * import ReactNative from 'react-native'; * 在调用之前 * ReactNative.findNodeHandle() * 否则应用程序将崩溃
2021-03-24 23:53:23
@miracle2k - 我有一个功能可以在输入模糊时重置滚动视图位置,即当键盘关闭时。也许这对你的情况有帮助?
2021-03-28 23:53:23
@Sherlock 模糊滚动视图重置功能是什么样的?顺便说一下,很棒的解决方案:)
2021-04-04 23:53:23

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

当心KeyboardAvoidingView,它只是不容易使用。它并不总是像您期望的那样运行。文档几乎不存在。
2021-03-22 23:53:23
我遇到的问题是,KeyboardAvoidingView 在我的 iPhone 6 模拟器上测量键盘高度为 65,所以我的视图仍然隐藏在键盘后面。
2021-03-23 23:53:23
在 React Native v0.65 中,这里是KeyboardAvoidingView
2021-03-25 23:53:23
医生和行为现在越来越好
2021-04-04 23:53:23
我可以管理它的唯一方法是通过触发的底部填充方法 DeviceEventEmitter.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
2021-04-05 23:53:23

我们结合了一些来自 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;
有什么简单/明显的方法可以防止键盘在 iOS 模拟器中显示?
2021-03-13 23:53:23
在此处尝试修改后的版本:gist.github.com/dbasedow/f5713763802e27fbde3fc57a600adcd3我相信这更好,因为它不依赖于我认为是脆弱的 imo 的任何超时。
2021-03-31 23:53:23
你试过 Command+K (Hardware->Keyboard->Toggle Software Keboard) 吗?
2021-04-08 23:53:23

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

  1. 在 XCode 中,在项目导航器中,右键单击 Libraries ➜ Add Files to [your project's name] 转到 node_modules ➜ react-native-keyboardevents 并添加 .xcodeproj 文件
  2. 在 XCode 的项目导航器中,选择您的项目。将keyboardevents 项目中的lib*.a 添加到项目的构建阶段➜ 将二进制文件与库链接在项目导航器中单击您之前添加的.xcodeproj 文件,然后转到构建设置选项卡。确保打开“全部”(而不是“基本”)。查找 Header Search Paths 并确保它包含 $(SRCROOT)/../react-native/React 和 $(SRCROOT)/../../React - 将两者标记为递归。
  3. 运行你的项目 (Cmd+R)

然后回到 javascript 领域:

您需要导入 react-native-keyboardevents。

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

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

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

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

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

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

react-native@0.11.0-rc 现在通过 DeviceEventEmitter 发送键盘事件(例如,“keyboardWillShow”),因此您可以为这些事件注册侦听器。但是,在处理 ListView 时,我发现在 ListView 的滚动视图上调用 scrollTo() 效果更好:this.listView.getScrollResponder().scrollTo(rowID * rowHeight); 当它收到 onFocus 事件时,它会在行的 TextInput 上调用。
2021-03-29 23:53:23
这个答案不再有效,因为 RCTDeviceEventEmitter 完成了这项工作。
2021-04-10 23:53:23
看到代码示例/有关如何制作动画的更多信息会很棒。跳转非常笨拙,并且仅使用“将显示”和“确实显示”方法,我无法弄清楚如何猜测键盘动画的长度或“将显示”的高度。
2021-04-11 23:53:23

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