使用useSafeArea挂钩时,反应原生Android文本输入问题



我制作了自己的侧模态,如下代码所示。它接受一个子组件,然后该子组件将被呈现为模态的内容。它在web和ios上正常工作,但在Android上,当我传递任何包含文本输入组件的子组件时,都会出现问题。当我触摸文本输入组件时,键盘会立即出现并消失,而且当我看到值返回到初始值时,似乎还会再次渲染子组件。

这很奇怪,因为当我传递完全相同的代码而不将其作为组件时,根本不会发生这种情况。

更奇怪的是,我的模态在更宽的屏幕上被设置为一定的宽度,而更小的屏幕在全视图中渲染模态。只有当它在众目睽睽之下时,问题才会出现。在Landscape上,键盘似乎没有什么不同,也没有任何问题。

如果有人能帮助我,我将负债累累。

SideModal.js

import React, { useEffect, useState, useRef } from "react";
import { useSafeArea } from "react-native-safe-area-context";
import { View, Animated, Dimensions } from "react-native";
import { Icon } from "react-native-elements";
import { styles } from "../../styles/globalStyle";
import { TouchableOpacity } from "react-native-gesture-handler";
//This Modal should have below props mandatory
// 1. children component, 2. isVisble, 3. setIsVisble, 4. size, 5, limit
//This Modal should always reside in SafeAreaView
const SideModal = props => {
const slideOut = useRef(new Animated.Value(0)).current;
const [dimensions, setDimensions] = useState({
window: Dimensions.get("window"),
});
const insets = useSafeArea();
let size = 0;
if (dimensions.window.width < props.limit) {
size = dimensions.window.width;
} else {
size = props.size;
}
useEffect(() => {
Animated.timing(slideOut, {
toValue: -size,
duration: 300,
useNativeDriver: true,
}).start();
return function cleanup() {
Animated.timing(slideOut).reset();
};
}, [slideOut]);
const disappear = () => {
Animated.timing(slideOut, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start(({ finished }) => {
props.setIsVisble(null);
});
};
useEffect(() => {
Dimensions.addEventListener("change", disappear);
return () => {
Dimensions.removeEventListener("change", disappear);
};
});
return (
<View style={[styles.modalContainer]}>
<View
onStartShouldSetResponder={() => disappear()}
style={styles.modalBackDrop}
>
<TouchableOpacity
onPress={() => disappear()}
style={{ width: "100%", height: "100%" }}
></TouchableOpacity>
</View>
<Animated.View
style={[
styles.modalContent,
{
paddingTop: insets.top,
marginRight: -size,
width: size,
transform: [{ translateX: slideOut }],
},
]}
>
<Icon
containerStyle={{
marginTop: 5,
marginBottom: -47,
zIndex: 1,
alignSelf: "flex-end",
}}
iconStyle={{
marginRight: 10,
opacity: 0.8,
}}
name="clear"
type="material"
color="#2E394B"
size={42}
onPress={() => disappear()}
/>
{props.children}
</Animated.View>
</View>
);
};
export default SideModal;

Main.js-直接将JSX作为子组件,没有问题

{isVisible == 2 && (
<SideModal
isVisible={isVisible}
setIsVisble={setIsVisble}
size={400}
limit={600}
>
<View>
<TextInput />
</View>
</SideModal>
)}

Main.js-将组件自定义为子组件,是的问题

const SampleView = () => {
return(
<View>
<TextInput/>
</View>
)
};
{isVisible == 2 && (
<SideModal
isVisible={isVisible}
setIsVisble={setIsVisble}
size={400}
limit={600}
>
<SampleView/>
</SideModal>
)}

样式

modalContainer: {
position: "absolute",
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "flex-end",
overflow: "hidden",
zIndex: 1,
elevation: 2,
},
modalBackDrop: {
width: "100%",
height: "100%",
position: "absolute",
},
modalContent: {
shadowOpacity: 0.75,
shadowRadius: 10,
shadowColor: "#cccccc",
shadowOffset: { height: 0, width: 0 },
elevation: 10,
zIndex: 4,
backgroundColor: "#ffffff",
height: "100%",
display: "flex",
},

我完全不知道这个问题是从哪里来的。。我在这个项目中使用Expo SDK,所以我的react原生版本可能是个问题。。?

请开导我!

环境

  • 在2台安卓设备和1台iphone6s上进行测试
  • React Native 0.62
  • Expo SDK 38

好的,我终于解决了这个问题。

请参阅下面的代码。

导致问题

import React from "react";
import { Text, View, TextInput } from "react-native";
import { useSafeArea } from "react-native-safe-area-context";
const Test = () => {
const insets = useSafeArea();
const MyInputView = () => {
return (
<View>
<TextInput placeholder="input" />
</View>
);
};
return (
<View
style={{
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
display: "flex",
}}
>
<MyInputView /> // Pass Children Component
</View>
);
};
export default Test;

没有问题#1

import React from "react";
import { Text, View, TextInput } from "react-native";
import { useSafeArea } from "react-native-safe-area-context";
const Test = () => {
const insets = useSafeArea();
const MyInputView = () => {
return (
<View>
<TextInput placeholder="input" />
</View>
);
};
return (
<View
style={{
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
display: "flex",
}}
>
<View>
<TextInput placeholder="input" /> //Pass JSX Directly
</View>
</View>
);
};
export default Test;

没有问题#2-我的选择

import React from "react";
import { Text, View, TextInput } from "react-native";
import { useSafeArea } from "react-native-safe-area-context";
const Test = () => {
const Wrapper = props => {
const insets = useSafeArea();
return (
<View
style={{
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
display: "flex",
}}
>
{props.children}
</View>
);
};
const MyInputView = () => {
return (
<View>
<TextInput placeholder="input" />
</View>
);
};
return (
<Wrapper>
<MyInputView />
</Wrapper>
);
};
export default Test;

所以我认为这是一个错误,因为这只能在Android设备上复制。实际上,这可能是最新的react原生版本上修复的一个错误,但由于我使用Expo,我一直使用较低的版本。

当您在屏幕中的顶级组件中使用useSafeArea((Hook(或useSafeAreaInsets(声明变量,然后使用包含TextInput的自定义组件时,就会出现问题。即使不使用变量,如果声明了它,也会导致问题。如果在一个单独的组件中声明钩子,或者直接将JSX作为包含TextInput的子组件传递,那么问题就解决了。我选择制作一个单独的包装器组件,因为子组件必须有自己的道具,而直接编写JSX确实让代码看起来很脏。

我完全不知道它为什么这么做,但由于这个问题还重置了TextInput组件,我想Android设备上的Hook和组件之间存在某种冲突。

如果有人遇到这个问题,希望这能节省他们3天的时间。

最新更新