IT story

TextInput에 포커스가있을 때 키보드 뒤에서 창을 자동으로 슬라이드하는 방법은 무엇입니까?

hot-time 2020. 9. 9. 20:16
반응형

TextInput에 포커스가있을 때 키보드 뒤에서 창을 자동으로 슬라이드하는 방법은 무엇입니까?


네이티브 앱이 창을 자동으로 스크롤하는이 해킹을 보았지만 반응 네이티브를위한 가장 좋은 방법이 궁금합니다 ... 필드가 포커스를 받고 뷰에서 낮은 위치에 놓이면 키보드가 텍스트 필드를 덮을 것입니다. . 이 문제는 예제 UIExplorer의 TextInputExample.js보기에서 볼 수 있습니다. 누구에게 좋은 해결책이 있습니까?


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

그런 다음 렌더링 함수에서 :

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

이것은 RCTDeviceEventEmitter키보드 이벤트 및 크기 조정을 위해를 사용 하고을 사용하여 구성 요소의 위치를 ​​측정하고 RCTUIManager.measureLayout에서 필요한 정확한 스크롤 이동을 계산합니다 scrollResponderInputMeasureAndScrollToKeyboard.

additionalOffset특정 UI 디자인의 필요에 맞게 매개 변수 를 가지고 놀 수 있습니다 .


Facebook 은이 문제를 해결하기 위해 반응 네이티브 0.29에서 오픈 소스 KeyboardAvoidingView 입니다. 문서 및 사용 예는 여기 에서 찾을 수 있습니다 .


우리는 React-native-keyboard-spacer 코드 형태와 @Sherlock의 코드를 결합하여 TextInput 요소가있는 모든 View를 감싸는 KeyboardHandler 구성 요소를 만들었습니다. 매력처럼 작동합니다! :-)

/**
 * 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;

먼저 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 파일을 클릭하고 빌드 설정 탭으로 이동합니다. '기본'대신 '모두'가 켜져 있는지 확인합니다. 헤더 검색 경로를 찾아서 $ (SRCROOT) /../ react-native / React 및 $ (SRCROOT) /../../ React를 모두 포함하는지 확인하십시오. 둘 다 재귀로 표시하십시오.
  3. 프로젝트 실행 (Cmd + R)

그런 다음 자바 스크립트 땅으로 돌아갑니다.

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-keyboard-aware-scroll-view가 문제를 해결했습니다. GitHub의 react-native-keyboard-aware-scroll-view


이 시도:

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

...

그것은 나를 위해 일했습니다. 보기는 기본적으로 키보드가 표시 될 때 축소되고 숨겨지면 다시 자랍니다.


언급하고 싶은데, 이제 KeyboardAvoidingViewRN에 있습니다. 가져 와서 RN의 다른 모듈로 사용하십시오.

다음은 RN의 커밋 링크입니다.

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

0.29.0부터 사용 가능

UIExplorer에 대한 예제도 포함되어 있습니다.


늦었을 수도 있지만 최상의 솔루션은 네이티브 라이브러리 인 IQKeyboardManager 를 사용하는 것입니다.

데모 프로젝트에서 iOS 프로젝트로 IQKeyboardManager 디렉토리를 드래그 앤 드롭하면됩니다. 그게 다야. 또한 isToolbar가 활성화 된 일부 valus 또는 AppDelegate.m 파일에서 텍스트 입력과 키보드 사이의 공간을 설정할 수 있습니다. 사용자 지정에 대한 자세한 내용은 내가 추가 한 GitHub 페이지 링크에 있습니다.


TextInput.onFocus 및 ScrollView.scrollTo를 사용했습니다.

...
<ScrollView ref="scrollView">
...
<TextInput onFocus={this.scrolldown}>
...
scrolldown: function(){
  this.refs.scrollView.scrollTo(width*2/3);
},

스티븐

높이가 키보드가 나타나는 것과 똑같은 속도로 움직이지 않아도 괜찮다면 LayoutAnimation을 사용하여 최소한 높이가 제자리에 들어 가지 않도록 할 수 있습니다. 예 :

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

몇 가지 예제 애니메이션은 다음과 같습니다 (위의 스프링을 사용하고 있습니다).

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의 대답을 참조하십시오. react-native 0.11부터 키보드 크기 조정은 내장 기능을 사용하여 해결할 수 있습니다.


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

Attach a onFocus listener on your inputs

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

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


I'm using a simpler method, but it's not animated yet. I have a component state called "bumpedUp" which I default to 0, but set to 1 when the textInput gets focus, like this:

On my textInput:

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

I also have style that gives the wrapping container of everything on that screen a bottom margin and negative top margin, like this:

mythingscontainer: {
  flex: 1,
  justifyContent: "center",
  alignItems: "center",
  flexDirection: "column",
},
bumpedcontainer: {
  marginBottom: 210,
  marginTop: -210,
},

And then on the wrapping container, I set the styles like this:

<View style={[styles.mythingscontainer, this.state.bumpedUp && styles.bumpedcontainer]}>

So, when the "bumpedUp" state gets set to 1, the bumpedcontainer style kicks in and moves the content up.

Kinda hacky and the margins are hardcoded, but it works :)


I use brysgo answer to raise the bottom of my scrollview. Then I use the onScroll to update the current position of the scrollview. I then found this React Native: Getting the position of an element to get the position of the textinput. I then do some simple math to figure out if the input is in the current view. Then I use scrollTo to move the minimum amount plus a margin. It's pretty smooth. Heres the code for the scrolling portion:

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

I also meet this question. Finally, I resolve it by defining the height of each scene, such as:

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

And, I also use a third-party module https://github.com/jaysoo/react-native-extra-dimensions-android to get the real height.

참고URL : https://stackoverflow.com/questions/29313244/how-to-auto-slide-the-window-out-from-behind-keyboard-when-textinput-has-focus

반응형