UNPKG

react-native-keyboard-accessory-tweaked

Version:

A React Native Keyboard Accessory (View, Navigation) Component. Sticky views on keyboard.

270 lines (238 loc) 6.78 kB
import React, { Component } from "react"; import PropTypes from "prop-types"; import { View, Keyboard, LayoutAnimation, Platform, StyleSheet, ViewPropTypes, Dimensions } from "react-native"; const accessoryAnimation = (duration, easing, animationConfig = null) => { if (animationConfig) { if (typeof animationConfig === "function") { return animationConfig(duration, easing); } return animationConfig; } if (Platform.OS === "android") { return { duration: 200, create: { duration: 200, type: LayoutAnimation.Types.linear, property: LayoutAnimation.Properties.opacity }, update: { type: LayoutAnimation.Types.linear } }; } return LayoutAnimation.create( duration, LayoutAnimation.Types[easing], LayoutAnimation.Properties.opacity ); }; const { height, width } = Dimensions.get("window"); const isSafeAreaSupported = Platform.OS === "ios" && (height > 800 || width > 800); class KeyboardAccessoryView extends Component { constructor(props) { super(props); this.state = { keyboardHeight: 0, accessoryHeight: 50, visibleAccessoryHeight: 50, isKeyboardVisible: false }; } componentDidMount() { const keyboardShowEvent = Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow"; const keyboardHideEvent = Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide"; this.keyboardShowEventListener = Keyboard.addListener( keyboardShowEvent, this.handleKeyboardShow ); this.keyboardHideEventListener = Keyboard.addListener( keyboardHideEvent, this.handleKeyboardHide ); } componentWillUnmount() { this.keyboardShowEventListener.remove(); this.keyboardHideEventListener.remove(); } handleChildrenLayout = layoutEvent => { this.setState({ visibleAccessoryHeight: layoutEvent.nativeEvent.layout.height, accessoryHeight: this.props.alwaysVisible || this.state.isKeyboardVisible ? layoutEvent.nativeEvent.layout.height : 0 }); }; handleKeyboardShow = keyboardEvent => { if (!keyboardEvent.endCoordinates) { return; } const keyboardHeight = Platform.select({ ios: keyboardEvent.endCoordinates.height, android: this.props.androidAdjustResize ? 0 : keyboardEvent.endCoordinates.height }); const keyboardAnimate = () => { const { animationConfig, animateOn } = this.props; if (animateOn === "all" || Platform.OS === animateOn) { LayoutAnimation.configureNext( accessoryAnimation( keyboardEvent.duration, keyboardEvent.easing, animationConfig ) ); } this.setState({ isKeyboardVisible: true, keyboardHeight: keyboardHeight }); }; if ( Platform.OS === "ios" || typeof this.props.onKeyboardShowDelay !== "number" ) { keyboardAnimate(); } else { setTimeout(() => { keyboardAnimate(); }, this.props.onKeyboardShowDelay); } this.setState({ isKeyboardVisible: true, keyboardHeight: keyboardHeight, accessoryHeight: this.state.visibleAccessoryHeight }); if (this.props.onKeyboardShow) { this.props.onKeyboardShow(); } }; handleKeyboardHide = keyboardEvent => { const { animateOn, animationConfig } = this.props; if (animateOn === "all" || Platform.OS === animateOn) { LayoutAnimation.configureNext( animationConfig || accessoryAnimation( keyboardEvent.duration, keyboardEvent.easing, animationConfig ) ); } this.setState({ isKeyboardVisible: false, keyboardHeight: 0, accessoryHeight: this.props.alwaysVisible ? this.state.visibleAccessoryHeight : 0 }); if (this.props.onKeyboardHide) { this.props.onKeyboardHide(); } }; render() { const { isKeyboardVisible, accessoryHeight, keyboardHeight } = this.state; const { bumperHeight, alwaysVisible, visibleOpacity, hiddenOpacity, hideBorder, style, inSafeAreaView, safeAreaBumper, avoidKeyboard } = this.props; const visibleHeight = accessoryHeight + (avoidKeyboard ? keyboardHeight : 0); const applySafeArea = isSafeAreaSupported && inSafeAreaView; const isChildRenderProp = typeof this.props.children === "function"; return ( <View style={{ height: isKeyboardVisible || alwaysVisible ? visibleHeight : 0 }} pointerEvents="box-none" > <View style={[ styles.accessory, !hideBorder && styles.accessoryBorder, style, { opacity: isKeyboardVisible || alwaysVisible ? visibleOpacity : hiddenOpacity, bottom: keyboardHeight - bumperHeight - (applySafeArea ? 20 : 0), height: accessoryHeight + bumperHeight + (applySafeArea ? (!isKeyboardVisible ? 20 : -10) : 0) } ]} pointerEvents="box-none" > <View onLayout={this.handleChildrenLayout} pointerEvents="box-none"> {isChildRenderProp ? this.props.children({ isKeyboardVisible }) : this.props.children} </View> </View> </View> ); } } KeyboardAccessoryView.propTypes = { style: (View.propTypes || ViewPropTypes).style, animateOn: PropTypes.oneOf(["ios", "android", "all", "none"]), animationConfig: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), bumperHeight: PropTypes.number, visibleOpacity: PropTypes.number, hiddenOpacity: PropTypes.number, onKeyboardShowDelay: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), androidAdjustResize: PropTypes.bool, alwaysVisible: PropTypes.bool, hideBorder: PropTypes.bool, inSafeAreaView: PropTypes.bool, avoidKeyboard: PropTypes.bool, onKeyboardShow: PropTypes.func, onKeyboardHide: PropTypes.func }; KeyboardAccessoryView.defaultProps = { animateOn: "ios", bumperHeight: 15, visibleOpacity: 1, hiddenOpacity: 0, androidAdjustResize: false, alwaysVisible: false, hideBorder: false, inSafeAreaView: false, avoidKeyboard: false }; const styles = StyleSheet.create({ accessory: { position: "absolute", right: 0, left: 0, backgroundColor: "#EFF0F1" }, accessoryBorder: { borderTopWidth: 1, borderTopColor: "rgba(0,0,0,0.2)" } }); export default KeyboardAccessoryView;