Я видел этот прием для нативных приложений для автоматической прокрутки окна, но мне интересно, как это сделать в React Native ... Когда <TextInput>
поле получает фокус и располагается низко в представлении, клавиатура закрывает текстовое поле.
Вы можете увидеть эту проблему в примере представления UIExplorer TextInputExample.js
.
Есть у кого-нибудь хорошее решение?
Ответы:
Ответ 2017
KeyboardAvoidingView
, Вероятно, лучший способ идти. Ознакомьтесь с документацией здесь . Это действительно просто по сравнению сKeyboard
модулем, который дает разработчику больше возможностей для управления анимацией. Спенсер Карли продемонстрировал все возможные способы в своем блоге .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> ) }
При этом используются
RCTDeviceEventEmitter
события клавиатуры и размер, измеряется позиция используемого компонентаRCTUIManager.measureLayout
и вычисляется точное движение прокрутки, необходимое вscrollResponderInputMeasureAndScrollToKeyboard
.Вы можете поэкспериментировать с
additionalOffset
параметром, чтобы он соответствовал потребностям вашего конкретного дизайна пользовательского интерфейса.источник
import {findNodeHandle} from 'react-native'
stackoverflow.com/questions/37626851/…Чтобы решить эту проблему, Facebook открыл исходный код
KeyboardAvoidingView
в react native 0.29. Документацию и пример использования можно найти здесь .источник
DeviceEventEmitter.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
Мы объединили часть кода формы react-native-keyboard-spacer и код из @Sherlock, чтобы создать компонент KeyboardHandler, который можно обернуть вокруг любого View с элементами TextInput. Работает как шарм! :-)
/** * 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;
источник
Сначала вам нужно установить response-native-keyboardevents .
Затем вернемся в страну javascript:
Вам необходимо импортировать файл response-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 анимации, но для простоты мы просто настраиваем после анимации.
источник
this.listView.getScrollResponder().scrollTo(rowID * rowHeight);
для TextInput строки, когда он получает событие onFocus.response-native-keyboard-aware-scroll-view решил проблему для меня. реакция-родная-клавиатура-осведомленная-прокрутка-просмотр на GitHub
источник
Попробуй это:
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>); }
...
У меня это сработало. Вид в основном сжимается при отображении клавиатуры и снова увеличивается, когда она скрыта.
источник
Просто хотел упомянуть, теперь есть
KeyboardAvoidingView
в РН есть. Просто импортируйте его и используйте как любой другой модуль в RN.Вот ссылка на коммит в RN:
https://github.com/facebook/react-native/commit/8b78846a9501ef9c5ce9d1e18ee104bfae76af2e
Доступно с версии 0.29.0
Они также включили пример на UIExplorer.
источник
Возможно, уже поздно, но лучшее решение - использовать собственную библиотеку IQKeyboardManager.
Просто перетащите каталог IQKeyboardManager из демонстрационного проекта в свой проект iOS. Вот и все. Также вы можете настроить некоторые значения, например isToolbar, или расстояние между вводом текста и клавиатурой в файле AppDelegate.m. Более подробная информация о настройке находится в добавленной мной ссылке на страницу GitHub.
источник
Я использовал TextInput.onFocus и ScrollView.scrollTo.
... <ScrollView ref="scrollView"> ... <TextInput onFocus={this.scrolldown}> ... scrolldown: function(){ this.refs.scrollView.scrollTo(width*2/3); },
источник
@Стивен
Если вы не против, чтобы высота анимировалась с той же скоростью, что и клавиатура, вы можете просто использовать LayoutAnimation, чтобы по крайней мере высота не встала на место. например
импортируйте LayoutAnimation из react-native и добавьте следующие методы в свой компонент.
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); },
Вот несколько примеров анимации (я использую весеннюю выше):
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, }, }, }, };
ОБНОВИТЬ:
См. Ответ @sherlock ниже, начиная с response-native 0.11 изменение размера клавиатуры может быть решено с использованием встроенных функций.
источник
Вы можете объединить несколько методов в нечто более простое.
Прикрепите прослушиватель onFocus к своим входам
<TextInput ref="password" secureTextEntry={true} onFocus={this.scrolldown.bind(this,'password')} />
Наш метод прокрутки вниз выглядит примерно так:
scrolldown(ref) { const self = this; this.refs[ref].measure((ox, oy, width, height, px, py) => { self.refs.scrollView.scrollTo({y: oy - 200}); }); }
Это говорит нашему представлению прокрутки (не забудьте добавить ссылку), чтобы прокрутить вниз до позиции нашего сфокусированного ввода - 200 (это примерно размер клавиатуры)
componentWillMount() { this.keyboardDidHideListener = Keyboard.addListener( 'keyboardWillHide', this.keyboardDidHide.bind(this) ) } componentWillUnmount() { this.keyboardDidHideListener.remove() } keyboardDidHide(e) { this.refs.scrollView.scrollTo({y: 0}); }
Здесь мы сбрасываем нашу прокрутку обратно наверх,
источник
Я использую более простой метод, но он еще не анимирован. У меня есть состояние компонента под названием "bumpedUp", которое по умолчанию равно 0, но устанавливается в 1, когда textInput получает фокус, например:
На моем textInput:
У меня также есть стиль, который дает упаковочному контейнеру всего на этом экране нижнее поле и отрицательное верхнее поле, например:
mythingscontainer: { flex: 1, justifyContent: "center", alignItems: "center", flexDirection: "column", }, bumpedcontainer: { marginBottom: 210, marginTop: -210, },
А затем в контейнере для упаковки я установил такие стили:
<View style={[styles.mythingscontainer, this.state.bumpedUp && styles.bumpedcontainer]}>
Итак, когда состояние «bumpedUp» становится равным 1, срабатывает стиль bumpedcontainer и перемещает контент вверх.
Kinda hacky и поля жестко запрограммированы, но это работает :)
источник
Я использую brysgo answer, чтобы поднять нижнюю часть прокрутки. Затем я использую onScroll, чтобы обновить текущую позицию прокрутки. Затем я нашел этот React Native: получение позиции элемента для получения позиции текстового ввода. Затем я выполняю простую математику, чтобы выяснить, находится ли ввод в текущем представлении. Затем я использую scrollTo, чтобы переместить минимальную сумму плюс маржа. Это довольно гладко. Вот код для прокручиваемой части:
focusOn: function(target) { return () => { var handle = React.findNodeHandle(this.refs[target]); UIManager.measureLayoutRelativeToParent( handle, (e) => {console.error(e)}, (x,y,w,h) => { var offs = this.scrollPosition + 250; var subHeaderHeight = (Sizes.width > 320) ? Sizes.height * 0.067 : Sizes.height * 0.077; var headerHeight = Sizes.height / 9; var largeSpace = (Sizes.height - (subHeaderHeight + headerHeight)); var shortSpace = largeSpace - this.keyboardOffset; if(y+h >= this.scrollPosition + shortSpace) { this.refs.sv.scrollTo(y+h - shortSpace + 20); } if(y < this.scrollPosition) this.refs.sv.scrollTo(this.scrollPosition - (this.scrollPosition-y) - 20 ); } ); }; },
источник
Я тоже встречаю этот вопрос. Наконец, я решаю это, определяя высоту каждой сцены, например:
<Navigator ... sceneStyle={{height: **}} />
И я также использую сторонний модуль https://github.com/jaysoo/react-native-extra-dimensions-android, чтобы получить реальную высоту.
источник