React-native Борьба с множественной текстовой обработкой, появлением клавиатуры и scrollView [duplicate]

85
задан McG 28 March 2015 в 04:12
поделиться

14 ответов

Просто хотел упомянуть, теперь в RN есть KeyboardAvoidingView. Просто импортируйте его и используйте его как любой другой модуль в RN.

Вот ссылка на фиксацию на RN:

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

Он доступен из 0.29.0

. Они также включили пример в UIExplorer.

4
ответ дан Aakash Sigdel 31 August 2018 в 15:39
поделиться

Возможно, это поздно, но лучшим решением является использование родной библиотеки, IQKeyboardManager

Просто перетащите каталог IQKeyboardManager из демонстрационного проекта в проект iOS. Вот и все. Также вы можете настроить некоторый valus, включенный isToolbar, или пробел между текстовым вводом и клавиатурой в файле AppDelegate.m. Более подробная информация о настройке содержится в ссылке на страницу GitHub, которую я добавил.

4
ответ дан Adrian Zghibarta 31 August 2018 в 15:39
поделиться

response-native-keyboard-aware-scroll-view решила проблему для меня. реагировать-родной-клавиатурой-прокрутки-просмотр на GitHub

7
ответ дан amirfl 31 August 2018 в 15:39
поделиться

Сначала вам нужно установить response-native-keysevents .

  1. В XCode в навигаторе проекта щелкните правой кнопкой мыши Библиотеки ➜ Добавьте файлы в [название вашего проекта ] Перейдите к node_modules ➜ response-native-keyboardevents и добавьте файл .xcodeproj
  2. . В XCode в навигаторе проекта выберите свой проект. Добавьте lib * .a из проекта keyboardevents в фазы сборки вашего проекта. ➜ Link Binary With Libraries. Щелкните файл .xcodeproj, добавленный ранее в навигаторе проекта, и перейдите на вкладку «Настройки сборки». Убедитесь, что включено «Все» (вместо «Basic»). Найдите пути поиска заголовков и убедитесь, что они содержат как $ (SRCROOT) /../ response-native / React, так и $ (SRCROOT) /../../ React-mark как рекурсивные.
  3. Запустите проект (Cmd + R)

Затем вернитесь в javascript land:

Вам нужно импортировать сообщения, реагирующие на реакцию на клавиатуре.

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, но для простоты мы просто настраиваем после анимации.

10
ответ дан brysgo 31 August 2018 в 15:39
поделиться

Я использую ответ brysgo, чтобы поднять нижнюю часть моего scrollview. Затем я использую onScroll для обновления текущей позиции scrollview. Затем я нашел это React Native: получение позиции элемента , чтобы получить позицию textinput. Затем я делаю некоторые простые математические вычисления, если вход находится в текущем виде. Затем я использую 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 );
                        }
                     );
                };
            },
0
ответ дан Community 31 August 2018 в 15:39
поделиться

@Stephen

Если вы не возражаете против того, чтобы анимация высоты была точно такой же, как на клавиатуре, вы можете просто использовать LayoutAnimation, чтобы по крайней мере высота не переходила место. например,

import LayoutAnimation from response-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,
      },
    },
  },
};

UPDATE:

См. ниже ответ @ sherlock, так как с учетом реакции 0.11 изменение размера клавиатуры может быть разрешено с использованием встроенных функций.

2
ответ дан deanmcpherson 31 August 2018 в 15:39
поделиться

Facebook open sourced KeyboardAvoidingView в ответе native 0.29 для решения этой проблемы. Пример документации и использования можно найти здесь здесь .

26
ответ дан farwayer 31 August 2018 в 15:39
поделиться

Мы объединили некоторые из кода формы response-native-keyboard-spacer и код из @Sherlock для создания компонента KeyboardHandler, который можно обернуть вокруг любого элемента View with 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;
12
ответ дан John kendall 31 August 2018 в 15:39
поделиться

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, чтобы соответствовать потребностям вашего конкретного дизайна пользовательского интерфейса.

78
ответ дан Milan Kamilya 31 August 2018 в 15:39
поделиться

Попробуйте следующее:

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

...

Это сработало для меня. Вид в основном сжимается, когда клавиатура отображается, и растет снова, когда она скрыта.

6
ответ дан pomo 31 August 2018 в 15:39
поделиться

Я также встречаю этот вопрос. Наконец, я разрешаю его, определяя высоту каждой сцены, например:

<Navigator ... sceneStyle={{height: **}} />

И также я использую сторонний модуль https: // github.com/jaysoo/react-native-extra-dimensions-android, чтобы получить реальную высоту.

0
ответ дан Renguang Dong 31 August 2018 в 15:39
поделиться

Вы можете объединить несколько методов в нечто более простое.

Приложить прослушиватель 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});
}

Здесь мы переустановили наш вид прокрутки вверх,

2
ответ дан SherylHohman 31 August 2018 в 15:39
поделиться

Я использовал TextInput.onFocus и ScrollView.scrollTo.

...
<ScrollView ref="scrollView">
...
<TextInput onFocus={this.scrolldown}>
...
scrolldown: function(){
  this.refs.scrollView.scrollTo(width*2/3);
},
2
ответ дан shohey1226 31 August 2018 в 15:39
поделиться

Я использую более простой метод, но он еще не анимирован. У меня есть состояние компонента, называемое «bumpedUp», которое по умолчанию равно 0, но устанавливается в 1, когда textInput получает фокус, например:

В моем тексте Вход:

onFocus={() => this.setState({bumpedUp: 1})}
onEndEditing={() => this.setState({bumpedUp: 0})}

У меня также есть стиль, который придает контейнеру для упаковки всего на этом экране нижнее поле и отрицательное верхнее поле, например:

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 и поля жестко закодированы, но он работает:)

0
ответ дан Stirman 31 August 2018 в 15:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: