네이티브 앱이 창을 자동으로 스크롤하는이 해킹을 보았지만 React Native에서 가장 좋은 방법이 궁금합니다. <TextInput>
필드가 포커스를 받고 뷰에서 낮은 위치 에 놓이면 키보드가 텍스트 필드를 덮을 것입니다.
이 문제는 예제 UIExplorer의 TextInputExample.js
보기 에서 볼 수 있습니다.
누구에게 좋은 해결책이 있습니까?
네이티브 앱이 창을 자동으로 스크롤하는이 해킹을 보았지만 React Native에서 가장 좋은 방법이 궁금합니다. <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 디자인의 요구 사항에 맞게 매개 변수 를 가지고 놀 수 있습니다 .
import {findNodeHandle} from 'react-native'
stackoverflow.com/questions/37626851/…
DeviceEventEmitter.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
우리는 React-native-keyboard-spacer 코드 형태와 @Sherlock의 코드를 결합하여 TextInput 요소가있는 모든 뷰를 감싸는 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 를 설치해야합니다 .
그런 다음 자바 스크립트 땅으로 돌아갑니다.
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를 사용하는 것도 가능하지만 간단하게하기 위해 애니메이션 후에 조정합니다.
this.listView.getScrollResponder().scrollTo(rowID * rowHeight);
. onFocus 이벤트를 수신하면 행의 TextInput에서 호출됩니다.
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>);
}
...
그것은 나를 위해 일했습니다. 보기는 기본적으로 키보드가 표시 될 때 축소되고 숨겨지면 다시 자랍니다.
언급하고 싶은데, 이제 KeyboardAvoidingView
RN에 있습니다. 가져 와서 RN의 다른 모듈로 사용하기 만하면됩니다.
다음은 RN의 커밋 링크입니다.
https://github.com/facebook/react-native/commit/8b78846a9501ef9c5ce9d1e18ee104bfae76af2e
0.29.0부터 사용 가능
UIExplorer에 대한 예제도 포함되어 있습니다.
늦었을 수도 있지만 최상의 솔루션은 기본 라이브러리 인 IQKeyboardManager 를 사용하는 것입니다.
데모 프로젝트에서 iOS 프로젝트로 IQKeyboardManager 디렉토리를 드래그 앤 드롭하면됩니다. 그게 다야. 또한 isToolbar가 활성화 된 일부 valus 또는 AppDelegate.m 파일에서 텍스트 입력과 키보드 사이의 공간을 설정할 수 있습니다. 사용자 지정에 대한 자세한 내용은 내가 추가 한 GitHub 페이지 링크에 있습니다.
스티븐
높이가 키보드가 나타나는 것과 똑같은 속도로 움직이지 않아도 괜찮다면 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부터 키보드 크기 조정은 내장 기능을 사용하여 해결할 수 있습니다.
몇 가지 방법을 좀 더 간단한 것으로 결합 할 수 있습니다.
입력에 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});
});
}
이것은 우리의 스크롤 뷰 (ref를 추가하는 것을 잊지 마십시오)에 초점을 맞춘 입력의 위치 인 200 (대략 키보드 크기)까지 스크롤하도록 지시합니다.
componentWillMount() {
this.keyboardDidHideListener = Keyboard.addListener(
'keyboardWillHide',
this.keyboardDidHide.bind(this)
)
}
componentWillUnmount() {
this.keyboardDidHideListener.remove()
}
keyboardDidHide(e) {
this.refs.scrollView.scrollTo({y: 0});
}
여기에서 스크롤 뷰를 다시 맨 위로 재설정합니다.
더 간단한 방법을 사용하고 있지만 아직 애니메이션이 적용되지 않았습니다. 기본적으로 0으로 설정된 "bumpedUp"이라는 구성 요소 상태가 있지만 textInput이 포커스를 받으면 다음과 같이 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 스타일이 시작되어 콘텐츠를 위로 이동합니다.
약간 해키하고 여백은 하드 코딩되어 있지만 작동합니다. :)
내 스크롤 뷰의 하단을 올리기 위해 brysgo 답변을 사용합니다. 그런 다음 onScroll을 사용하여 scrollview의 현재 위치를 업데이트합니다. 그런 다음이 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 도 사용합니다 .