android - React Native:Android 软键盘将 View 向上推
问题描述
我制作了一张自定义动画底页。它有两个捕捉点。它从屏幕顶部开始,如果向下滚动动画卡片,它将来到屏幕中间,再次向下滚动卡片,它将来到屏幕底部。如果用户用力向下滚动动画卡片,那么它将一直向下滚动。我将此组件制作为可重复使用的组件。
我制作了可重复使用的搜索组件。
我将这两个组件都导入了main-app组件。在Animated-Bottom-sheet中,我放置了Search-component。
我已经为键盘和Animated.View创造了条件
如果动画视图从屏幕中间移动到底部并搜索onFocus(出现键盘),则键盘将关闭。
如果动画视图位于屏幕底部并且搜索输入
onfocus
(出现键盘),那么它将移动屏幕中间的动画视图。对于这个逻辑,我做了Keyboard.addListener('keyboardDidHide',()=>{....})
我的这个逻辑在 IOS 中完美运行,但在 Android 中,它将所有元素推到屏幕顶部。
有很多关于 KeyboardAvoidingView 的建议,但就我而言,它不起作用。
在 react-native 的 android 的 AndroidManifest.xml 文件中。我做了android:windowSoftInputMode="adjustPan"
,它会听Keyboard.addListener('keyboardDidHide'
并将所有元素推到屏幕顶部,如果我做了android:windowSoftInputMode="adjustPan|adjustResize"
,它就不会听Event-lister
。结果,我的逻辑不起作用,它隐藏了 Android 键盘下的动画视图。根据RN-documentation,Event-lister only listen adjustResize or adjustPan
。
问题:
我真的不知道如何解决这个问题
Android 设备行为
代码演示
这是我的动画视图组件
import React, { useState } from "react";
import { StyleSheet, Dimensions, Platform, View, Keyboard } from "react-native";
import {
PanGestureHandler,
PanGestureHandlerGestureEvent,
} from "react-native-gesture-handler";
import Animated, {
useAnimatedGestureHandler,
useAnimatedStyle,
useSharedValue,
withTiming,
withSpring,
runOnJS,
Easing,
} from "react-native-reanimated";
import styled from "styled-components/native";
interface Props {
children: React.ReactNode;
}
const { height: SCREEN_HEIGHT } = Dimensions.get("screen");
const IPHONE_DEVICE_MIDDLE_SCREEN = Platform.OS === "ios" ? 4 : 4;
const IPHONE_DEVICE_BOTTOM_SCREEN = Platform.OS === "ios" ? 7.6 : 7.36;
const ANIMATED_DURATION = 300;
const LoadingContainer = styled.View`
height: ${SCREEN_HEIGHT - 300}px;
background-color: #fff;
justify-content: center;
`;
const ScrollBottomSheet = ({ children }: Props) => {
const contentTop = useSharedValue(SCREEN_HEIGHT);
const [bottomSheetState, setBottomSheetState] = useState("top");
// Event-listener
Keyboard.addListener("keyboardDidShow", () => {
if (bottomSheetState === "bottom") {
contentTop.value = withSpring(
SCREEN_HEIGHT * IPHONE_DEVICE_MIDDLE_SCREEN
);
}
});
const animatedStyle = useAnimatedStyle(() => {
"worklet";
return {
top: contentTop.value * 0.1,
bottom: 0,
};
});
const gestureHandler = useAnimatedGestureHandler(
{
onStart(_, context) {
context.translateY = contentTop.value;
},
onActive(event, context) {
contentTop.value = context.translateY + event.translationY;
},
onEnd(event, _) {
if (event.y > 0 && event.y < 200) {
// MIDDLE SCREEN LOGIC
contentTop.value = withTiming(
SCREEN_HEIGHT * IPHONE_DEVICE_MIDDLE_SCREEN,
{
duration: ANIMATED_DURATION,
easing: Easing.inOut(Easing.ease),
}
);
runOnJS(setBottomSheetState)("middle");
runOnJS(Keyboard.dismiss)(); // dismiss Keyboard
} else if (event.y > 200) {
// BOTTOM SCREEN LOGIC
contentTop.value = withTiming(
SCREEN_HEIGHT * IPHONE_DEVICE_BOTTOM_SCREEN,
{
duration: ANIMATED_DURATION,
easing: Easing.inOut(Easing.ease),
}
);
runOnJS(Keyboard.dismiss)();
runOnJS(setBottomSheetState)("bottom");
} else if (event.translationY < 0) {
contentTop.value = withTiming(SCREEN_HEIGHT, {
duration: ANIMATED_DURATION,
easing: Easing.inOut(Easing.ease),
});
runOnJS(setBottomSheetState)("top");
}
},
},
[contentTop]
);
return (
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.container, animatedStyle]}>
<View style={styles.grbber} />
{children}
</Animated.View>
</PanGestureHandler>
);
};
export default ScrollBottomSheet;
const styles = StyleSheet.create({
container: {
position: "absolute",
left: 0,
right: 0,
top: 0,
backgroundColor: "#fff",
shadowOffset: {
height: -6,
width: 0,
},
shadowOpacity: 0.1,
shadowRadius: 5,
borderTopEndRadius: 15,
borderTopLeftRadius: 15,
},
grbber: {
width: 80,
height: 5,
marginBottom: 4,
alignSelf: "center",
marginTop: 5,
borderTopWidth: 5,
borderTopColor: "#aaa",
},
});
搜索组件
import React, { useRef, useEffect } from "react";
import {
Animated,
KeyboardTypeOptions,
TextInputProps,
TextInput,
Text,
Keyboard,
} from "react-native";
import styled from "styled-components/native";
type Props = TextInputProps & {
text: string,
hint: string,
onChangeText?: ((text: string) => void) | undefined,
onClearText: () => void,
animatedStyle?: { height: Animated.AnimatedInterpolation },
keyboardType?: KeyboardTypeOptions,
autoFocus?: boolean,
};
const Container = styled(Animated.View)`
flex-direction: row;
background-color: grey;
border-radius: 6px;
align-items: center;
`;
const IconTouchableOpacity = styled.TouchableOpacity`
padding: 16px;
`;
const SearchInput = styled.TextInput`
flex: 1;
padding-right: 16px;
color: #fff;
font-size: 16px;
line-height: 20px;
height: 44px;
`;
const SearchBar = ({
text,
hint,
onChangeText,
onClearText,
animatedStyle,
keyboardType,
maxLength,
autoFocus,
}: Props) => {
const searchInput = useRef(null);
const onSearchPress = () => {
searchInput?.current?.focus();
};
useEffect(() => {
if (autoFocus) {
onSearchPress();
}
}, [autoFocus]);
return (
<Container accessible={false} style={animatedStyle}>
<SearchInput
ref={searchInput}
onChangeText={onChangeText}
value={text}
placeholder={hint}
maxLength={maxLength}
underlineColorAndroid={"transparent"}
placeholderTextColor={"grey"}
keyboardType={keyboardType}
autoFocus={autoFocus}
onKeyPress={() => hideKeyBoard}
/>
</Container>
);
};
export default SearchBar;
**应用组件
import React, { useState, useEffect } from "react";
import { StyleSheet, Button } from "react-native";
import { TouchableHighlight } from "react-native-gesture-handler";
import MapView from "react-native-maps";
import styled from "styled-components";
import ScrollBottomSheet from "./components/ActionSheet";
import SearchBar from "./components/SearchBar";
const initialRegion = {
latitudeDelta: 15,
longitudeDelta: 15,
latitude: 60.1098678,
longitude: 24.7385084,
};
export default function App() {
return (
<>
<MapView style={styles.mapStyle} initialRegion={initialRegion} />
<ScrollBottomSheet>
<SearchContainer>
<SearchBar hint={"search"} />
</SearchContainer>
</ScrollBottomSheet>
</>
);
}
const styles = StyleSheet.create({
mapStyle: {
height: "100%",
},
});
const SearchContainer = styled.View`
padding: 10px;
`;
解决方案
您是否尝试过使用 Animated.ScrollView 而不是 Animated.View?
推荐阅读
- python - 如何使用小的单个图像并在整个窗口中重复它以使用 tkinter GUI 使其成为背景图像?
- javascript - 使用 Formik 和 material-ui stepper 上传文件
- r - 部分适用于用于检查一列中的列值是否存在于另一列中的语句
- javascript - mongoDB - 从一个集合中获取数据并保存到另一个集合
- flutter - Flutter Image Cropper 无法加载资源
- python - 如何按值对两个列表的字典进行排序
- python - LINPROG 区别 MATLAB 和 Python
- python - 如何使用具有多对多关系的复选框来保存多个用户?
- kubernetes - 使用不存在的存储类创建 PersistentVolume 成功
- java - 如何操作 Java 的 BigIntegers