Widziałem ten sposób na automatyczne przewijanie okna przez aplikacje natywne, ale zastanawiam się, jak to zrobić w React Native ... Kiedy <TextInput>
pole zostanie wyróżnione i zostanie umieszczone nisko w widoku, klawiatura zakryje pole tekstowe.
Możesz zobaczyć ten problem na przykładzie TextInputExample.js
widoku UIExplorer .
Czy ktoś ma dobre rozwiązanie?
Odpowiedzi:
Odpowiedź z 2017 r
To
KeyboardAvoidingView
prawdopodobnie najlepszy sposób, aby teraz iść. Sprawdź dokumenty tutaj . Jest to naprawdę proste w porównaniu zKeyboard
modułem, który daje programistom większą kontrolę nad wykonywaniem animacji. Spencer Carli zademonstrował wszystkie możliwe sposoby na swoim blogu .Odpowiedź 2015
Prawidłowy sposób wykonania tego w programie
react-native
nie wymaga zewnętrznych bibliotek, wykorzystuje kod natywny i zawiera animacje.Najpierw zdefiniuj funkcję, która będzie obsługiwać
onFocus
zdarzenie dla każdegoTextInput
(lub dowolnego innego komponentu, do którego chcesz przewinąć):// 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); }
Następnie w funkcji renderującej:
render () { return ( <ScrollView ref='scrollView'> <TextInput ref='username' onFocus={this.inputFocused.bind(this, 'username')} </ScrollView> ) }
Używa
RCTDeviceEventEmitter
do zdarzeń klawiatury i zmiany rozmiaru, mierzy położenie komponentu przy użyciuRCTUIManager.measureLayout
i oblicza dokładny ruch przewijania wymagany wscrollResponderInputMeasureAndScrollToKeyboard
.Możesz bawić się tym
additionalOffset
parametrem, aby dopasować go do potrzeb konkretnego projektu interfejsu użytkownika.źródło
import {findNodeHandle} from 'react-native'
stackoverflow.com/questions/37626851/ ...Facebook open source
KeyboardAvoidingView
reaguje na natywne 0.29, aby rozwiązać ten problem. Dokumentację i przykład użycia można znaleźć tutaj .źródło
DeviceEventEmitter.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
Połączyliśmy część kodu w postaci reaguj-natywna-klawiatura-odstępnik i kod z @Sherlock, aby utworzyć komponent KeyboardHandler, który można zawinąć wokół dowolnego widoku z elementami TextInput. Działa jak marzenie! :-)
/** * 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;
źródło
Najpierw musisz zainstalować zdarzeniareak-native-keyboardevents .
Następnie z powrotem w krainie javascript:
Musisz zaimportować zdarzeniareak-native-keyboardevents.
var KeyboardEvents = require('react-native-keyboardevents'); var KeyboardEventEmitter = KeyboardEvents.Emitter;
Następnie w swoim widoku dodaj stan dla przestrzeni klawiatury i zaktualizuj nasłuchiwanie zdarzeń klawiatury.
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, }; },
Na koniec dodaj element dystansowy do funkcji renderowania pod wszystkim, aby gdy zwiększył rozmiar, podniósł swoje rzeczy.
<View style={{height: this.state.keyboardSpace}}></View>
Możliwe jest również użycie animacji API, ale dla uproszczenia dostosowujemy się po animacji.
źródło
this.listView.getScrollResponder().scrollTo(rowID * rowHeight);
jest wywoływane w wierszu TextInput, gdy odbiera zdarzenie onFocus.reakcja-native-keyboard-aware-scroll-view rozwiązała problem za mnie. React-native-keyboard-aware-scroll-view na GitHub
źródło
Spróbuj tego:
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>); }
...
U mnie to zadziałało. Widok zasadniczo kurczy się, gdy klawiatura jest wyświetlana, i odrasta, gdy jest ukryta.
źródło
Chciałem tylko wspomnieć, teraz jest
KeyboardAvoidingView
w RN. Po prostu zaimportuj go i używaj jak każdego innego modułu w RN.Oto link do zatwierdzenia na RN:
https://github.com/facebook/react-native/commit/8b78846a9501ef9c5ce9d1e18ee104bfae76af2e
Jest dostępny od 0.29.0
Zawarli również przykład na UIExplorer.
źródło
Może jest za późno, ale najlepszym rozwiązaniem jest użycie natywnej biblioteki IQKeyboardManager
Po prostu przeciągnij i upuść katalog IQKeyboardManager z projektu demonstracyjnego do projektu iOS. Otóż to. Możesz także skonfigurować niektóre wartości, takie jak włączony pasek narzędzi, lub odstęp między wprowadzaniem tekstu a klawiaturą w pliku AppDelegate.m. Więcej szczegółów na temat dostosowywania znajduje się w linku do strony GitHub, który dodałem.
źródło
Użyłem TextInput.onFocus i ScrollView.scrollTo.
... <ScrollView ref="scrollView"> ... <TextInput onFocus={this.scrolldown}> ... scrolldown: function(){ this.refs.scrollView.scrollTo(width*2/3); },
źródło
@Stephen
Jeśli nie masz nic przeciwko temu, by wysokość animacji była dokładnie taka sama, jak pojawia się klawiatura, możesz po prostu użyć LayoutAnimation, aby przynajmniej wysokość nie wskoczyła na miejsce. na przykład
zaimportuj LayoutAnimation z React-Native i dodaj następujące metody do swojego komponentu.
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); },
Oto kilka przykładowych animacji (używam wiosennej powyżej):
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, }, }, }, };
AKTUALIZACJA:
Zobacz odpowiedź @ sherlock poniżej, ponieważ odreak-native 0.11 zmiana rozmiaru klawiatury może być rozwiązana za pomocą wbudowanych funkcji.
źródło
Możesz połączyć kilka metod w coś prostszego.
Dołącz odbiornik onFocus do swoich danych wejściowych
<TextInput ref="password" secureTextEntry={true} onFocus={this.scrolldown.bind(this,'password')} />
Nasza metoda przewijania w dół wygląda mniej więcej tak:
scrolldown(ref) { const self = this; this.refs[ref].measure((ox, oy, width, height, px, py) => { self.refs.scrollView.scrollTo({y: oy - 200}); }); }
To mówi naszemu widokowi przewijania (pamiętaj, aby dodać ref), aby przewinął w dół do pozycji naszego skoncentrowanego wejścia - 200 (to mniej więcej rozmiar klawiatury)
componentWillMount() { this.keyboardDidHideListener = Keyboard.addListener( 'keyboardWillHide', this.keyboardDidHide.bind(this) ) } componentWillUnmount() { this.keyboardDidHideListener.remove() } keyboardDidHide(e) { this.refs.scrollView.scrollTo({y: 0}); }
Tutaj resetujemy nasz widok przewijania z powrotem do góry,
źródło
Używam prostszej metody, ale nie jest jeszcze animowana. Mam stan komponentu o nazwie „bumpedUp”, który domyślnie wynosi 0, ale jest ustawiony na 1, gdy fokus zostanie ustawiony na textInput, na przykład:
W moim tekście
Mam też styl, który nadaje opakowaniom wszystkiego na tym ekranie dolny i ujemny górny margines, na przykład:
mythingscontainer: { flex: 1, justifyContent: "center", alignItems: "center", flexDirection: "column", }, bumpedcontainer: { marginBottom: 210, marginTop: -210, },
Następnie na opakowaniu do pakowania ustawiam style w ten sposób:
<View style={[styles.mythingscontainer, this.state.bumpedUp && styles.bumpedcontainer]}>
Tak więc, gdy stan „bumpedUp” zostanie ustawiony na 1, styl bumpedcontainer włącza się i przesuwa zawartość w górę.
Trochę hacky i marginesy są zakodowane na stałe, ale działa :)
źródło
Używam odpowiedzi brysgo, aby podnieść dolną część widoku przewijania. Następnie używam onScroll, aby zaktualizować bieżącą pozycję widoku scrollview. Następnie znalazłem ten React Native: Pobieranie pozycji elementu, aby uzyskać pozycję wejścia tekstowego. Następnie wykonuję prostą matematykę, aby dowiedzieć się, czy dane wejściowe są w bieżącym widoku. Następnie używam scrollTo, aby przesunąć minimalną kwotę plus margines. Jest całkiem gładki. Oto kod części przewijanej:
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 ); } ); }; },
źródło
Ja też odpowiadam na to pytanie. Wreszcie rozwiązuję to, definiując wysokość każdej sceny, na przykład:
<Navigator ... sceneStyle={{height: **}} />
Używam również modułu innej firmy https://github.com/jaysoo/react-native-extra-dimensions-android, aby uzyskać rzeczywistą wysokość.
źródło