在react native開發中第一個最容易遇到的坑就是點選輸入框,ios的鍵盤遮擋住了輸入框,看不到輸入的內容。而直接使用第三方的庫解決這個問題的過程中又遇到了新的問題,github上開發的庫無法解決問題。所以就只能自行封裝一個來解決鍵盤遮擋輸入框的問題。
import React from 'react';
import {Animated, Dimensions, EmitterSubscription, Keyboard, Platform, TextInput, UIManager} from 'react-native';
import {NavigationEventSubscription, NavigationScreenProp} from 'react-navigation';
interface IState {
height: Animated.Value;
}
export interface KeyboardAvoidingViewProps {
navigation: NavigationScreenProp<any, any>;
onInputChange?: (onInput: boolean) => void;
// 固定鍵盤高度
fixedKeyboardHeight?: boolean;
// 固定上浮高度
fixedHeight?: number;
// 鍵盤加上高度
addHeight?: number;
}
export default class KeyboardAvoidingView extends React.Component<KeyboardAvoidingViewProps, IState> {
state = {
height: new Animated.Value(0),
onInput: false
}
private didFocus?: NavigationEventSubscription;
private willBlur?: NavigationEventSubscription;
private keyboardDidShowSub?: EmitterSubscription;
private keyboardDidHideSub?: EmitterSubscription;
componentDidMount() {
this.didFocus = this.props.navigation.addListener('didFocus', () => {
this.keyboardDidShowSub = Keyboard.addListener('keyboardDidShow', this.handleKeyboardDidShow);
this.keyboardDidHideSub = Keyboard.addListener('keyboardDidHide', this.handleKeyboardDidHide);
});
this.willBlur = this.props.navigation.addListener('willBlur', () => {
this.keyboardDidShowSub && this.keyboardDidShowSub.remove();
this.keyboardDidHideSub && this.keyboardDidHideSub.remove();
});
}
handleKeyboardDidShow = (event: any) => {
this.props.onInputChange && this.props.onInputChange(true);
if (Platform.OS != 'ios') return;
console.log('handleKeyboardDidShow');
const { height: windowHeight } = Dimensions.get('window');
const addHeight = this.props.addHeight || 0;
const keyboardHeight = event.endCoordinates.height + addHeight;
const currentlyFocusedField = TextInput.State.currentlyFocusedField();
console.log('currentlyFocusedField', currentlyFocusedField);
if (currentlyFocusedField == null) return;
if (this.props.fixedHeight != undefined) {
Animated.timing(
this.state.height,
{
toValue: -this.props.fixedHeight,
duration: 200,
useNativeDriver: true,
}
).start();
return;
}
if (this.props.fixedKeyboardHeight) {
console.log('keyboardHeight', keyboardHeight);
Animated.timing(
this.state.height,
{
toValue: -keyboardHeight,
duration: 200,
useNativeDriver: true,
}
).start();
return;
}
UIManager.measure(currentlyFocusedField, (originX, originY, width, height, pageX, pageY) => {
const fieldHeight = height;
const fieldTop = pageY;
const gap = (windowHeight - keyboardHeight) - (fieldTop + fieldHeight);
console.log('windowHeight', windowHeight, 'keyboardHeight', keyboardHeight, 'gap', gap, 'fieldTop', fieldTop, 'fieldHeight', fieldHeight);
if (gap >= 0) {
return;
}
Animated.timing(
this.state.height,
{
toValue: gap,
duration: 200,
useNativeDriver: true,
}
).start();
});
}
handleKeyboardDidHide = () => {
this.props.onInputChange && this.props.onInputChange(false);
if (Platform.OS != 'ios') return;
console.log('handleKeyboardDidHide');
Animated.timing(
this.state.height,
{
toValue: 0,
duration: 200,
useNativeDriver: true,
}
).start();
}
render() {
if (Platform.OS == 'ios') {
return (
<Animated.View style={{flex: 1, transform: [{translateY: this.state.height}]}}>
{this.props.children}
</Animated.View>
);
}
return this.props.children;
}
}
複製程式碼
需要注意的是KeyboardAvoidingView與react-navigation配合使用,在路由push後事件還在監聽,所以需要移除,然後等路由重新回來到當前頁面再重新監聽。
將元件包裹在檢視最上層即可
<KeyboardAvoidingView navigation={this.props.navigation}>
<View>
<TextInput />
...
</View>
</KeyboardAvoidingView>
複製程式碼