メモを編集する画面を実装
MemoEditScreenを作成
src/screensの中にMemoEditScreen.jsxを作成する。
MemoEditScreen.jsx
import React from 'react';
import { View, TextInput, StyleSheet } from 'react-native';
import AppBar from '../components/AppBar';
import CircleButton from '../components/CircleButton';
// eslint-disable-next-line react/function-component-definition
export default function MemoEditScreen() {
return (
<View style={styles.container}>
<AppBar />
<View style={styles.inputContainer}>
<TextInput value="買い物" multiline style={styles.input} />
</View>
<CircleButton name="check" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
inputContainer: {
paddingVertical: 30,
paddingHorizontal: 24,
flex: 1,
},
input: {
fontSize: 20,
lineHeight: 24,
flex: 1,
textAlignVertical: 'top',
},
});
スマホ画面で確認すると、こんな感じ。
カーソルを合わせると、キーボードが出てくる。
キーボードが出ると、右下にあったボタンが隠れてしまう。
これを回避するためにKeyboardAvoidingViewという便利な機能がある。
KeyboardAvoidingView
ReactNativeにはKeyboardAvoidingViewという便利な機能がある。
それを使うと、
MemoEditScreen.jsx
import React from 'react';
import { View, TextInput, StyleSheet, KeyboardAvoidingView } from 'react-native';
import AppBar from '../components/AppBar';
import CircleButton from '../components/CircleButton';
// eslint-disable-next-line react/function-component-definition
export default function MemoEditScreen() {
return (
<KeyboardAvoidingView style={styles.container} behavior="height">
<AppBar />
<View style={styles.inputContainer}>
<TextInput value="買い物" multiline style={styles.input} />
</View>
<CircleButton name="check" />
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
inputContainer: {
paddingVertical: 30,
paddingHorizontal: 24,
flex: 1,
},
input: {
fontSize: 20,
lineHeight: 24,
flex: 1,
textAlignVertical: 'top',
},
});
ボタンがキーボードで隠れなくなる。
KeybordAvoindingViewのバグ
キーボードのタイプを変更すると、ボタンが消えてしまうバグがある。
それを回避するために、
src/componentsの中にKeyboardSafeView.jsxファイルを作成する。
KeyboardSafeView.jsx
import React, { useRef, useState, useEffect } from 'react';
import {
Keyboard, Dimensions, Animated, ViewPropTypes,
} from 'react-native';
// eslint-disable-next-line import/no-extraneous-dependencies
import { node } from 'prop-types';
// eslint-disable-next-line react/function-component-definition
export default function KeyboardSafeView({ children, style }) {
const initialViewHeight = useRef(null);
const animatedViewHeight = useRef(null);
const [viewHeight, setViewHeight] = useState(null);
useEffect(() => {
Keyboard.addListener('keyboardDidShow', handleShow);
Keyboard.addListener('keyboardDidHide', handleHide);
return () => {
Keyboard.removeListener('keyboardDidShow', handleShow);
Keyboard.removeListener('keyboardDidHide', handleHide);
};
}, []);
useEffect(() => {
if ([initialViewHeight, animatedViewHeight, viewHeight].some((val) => val === null)) { return; }
// height is not supported with useNativeDriver: true
// https://github.com/react-native-community/react-native-modal/issues/163
if (viewHeight === initialViewHeight.current) {
Animated.timing(
animatedViewHeight.current,
{ toValue: initialViewHeight.current, duration: 300, useNativeDriver: false },
).start();
} else {
Animated.timing(
animatedViewHeight.current,
{ toValue: viewHeight, duration: 300, useNativeDriver: false },
).start();
}
}, [viewHeight]);
const handleShow = ({ endCoordinates }) => {
if (endCoordinates.height && initialViewHeight.current) {
const keyboardHeight = Dimensions.get('window').height - endCoordinates.screenY;
setViewHeight(initialViewHeight.current - keyboardHeight);
}
};
const handleHide = () => {
setViewHeight(initialViewHeight.current);
};
const handleLayout = ({ nativeEvent }) => {
if (!initialViewHeight.current) {
const { height } = nativeEvent.layout;
// keep viewHeight as null not to trigger useEffect on mounting.
// Don't do this: setViewHeight(height);
initialViewHeight.current = height;
animatedViewHeight.current = new Animated.Value(height);
}
};
const animatedStyle = viewHeight ? {
height: animatedViewHeight.current,
flex: 0,
} : {};
return (
<Animated.View style={[style, animatedStyle]} onLayout={handleLayout}>
{children}
</Animated.View>
);
}
KeyboardSafeView.propTypes = {
children: node.isRequired,
style: ViewPropTypes.style,
};
KeyboardSafeView.defaultProps = {
style: null,
};
KeyboadAvoidingViewの代わりに、このKeyboardSafeViewを使うと
キーボードのタイプを変更してもボタンが消えなくなる。