gpt4 book ai didi

javascript - 如何在 React Native Reanimated 中对键盘事件使用react?

转载 作者:行者123 更新时间:2023-11-28 03:28:25 26 4
gpt4 key购买 nike

我正在尝试做什么

我正在尝试创建一个动画间距/填充元素,该元素在显示或隐藏键盘时改变高度,以确保 TextInput 不会被键盘或使用 KeyboardAvoidingView< 避免键盘的按钮覆盖。/。如果按钮要覆盖输入,我只希望这个动画空间改变高度,否则,我不希望间距改变高度。这是设计要求。

我当前的解决方案

我之前可以使用 react-nativeAnimated API 实现此目的,但我想使用 react-native-reanimated获得在 UI 线程上运行所有内容的性能优势。我实际上有一个可行的解决方案,但是 UI 线程在动画期间下降到 50 fps 中间,所以我假设我做错了什么。

正如您将在下面的代码中看到的,我正在计算所有元素的高度,以查明锚定到键盘顶部的按钮是否与 TextInput 重叠。如果是这样,我会从文本上方的间距高度(animHeaderHeight)中减去重叠量。您应该能够复制粘贴此代码并运行它。如果您打开探查器并观看 UI 线程,请通过聚焦输入并点击返回来关闭动画来切换动画。动画有效,但会导致 UI 线程运行速度低于 60fps。

可重现的代码

我使用 expo init 启动了该项目。以下是软件包版本:

"expo": "^35.0.0",
"expo-constants": "~7.0.0",
"react": "16.8.3",
"react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz",
"react-native-gesture-handler": "~1.3.0",
"react-native-reanimated": "~1.2.0",

这是代码。

import React, { useEffect, useRef } from "react";
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Keyboard,
KeyboardEvent,
KeyboardEventName,
Platform,
TextInput,
SafeAreaView,
KeyboardAvoidingView,
LayoutChangeEvent,
Dimensions
} from "react-native";
import Animated, { Easing } from "react-native-reanimated";
import Constants from "expo-constants";

const DEVICE_HEIGHT = Dimensions.get("screen").height;
const STATUS_BAR_HEIGHT = Constants.statusBarHeight;
const HEADER_HEIGHT = 100;
const MAX_ANIMATED_HEIGHT = 75;
const BOTTOM_BUTTON_HEIGHT = 60;
const KEYBOARD_EASING = Easing.bezier(0.38, 0.7, 0.125, 1.0);

const {
Value,
Clock,
set,
block,
cond,
eq,
and,
neq,
add,
sub,
max,
startClock,
stopClock,
timing,
interpolate
} = Animated;

export default App = () => {
// These refs are used so the height calculations are only called once and don't cause re-renders
const wasKeyboardMeasured = useRef(false);
const wasContentMeasured = useRef(false);

const clock = new Clock();
const keyboardShown = new Value(-1);
const animKeyboardHeight = new Value(0);
const animContentHeight = new Value(0);

function handleLayout(e) {
if (!wasContentMeasured.current) {
// Set animated value and set ref measured flag true
const height = Math.floor(e.nativeEvent.layout.height);
wasContentMeasured.current = true;
animContentHeight.setValue(height);
}
}

useEffect(() => {
const handleKbdShow = (e: KeyboardEvent) => {
if (!wasKeyboardMeasured.current) {
// Set animated value and set ref measured flag true
const kbdHeight = Math.floor(e.endCoordinates.height);
wasKeyboardMeasured.current = true;
animKeyboardHeight.setValue(kbdHeight);
}
keyboardShown.setValue(1);
};
const handleKbdHide = () => {
keyboardShown.setValue(0
);
};

const kbdWillOrDid = Platform.select({ ios: "Will", android: "Did" });
const showEventName = `keyboard${kbdWillOrDid}Show`;
const hideEventName = `keyboard${kbdWillOrDid}Hide`;

Keyboard.addListener(showEventName, handleKbdShow);
Keyboard.addListener(hideEventName, handleKbdHide);

return () => {
Keyboard.removeListener(showEventName, handleKbdShow);
Keyboard.removeListener(hideEventName, handleKbdHide);
};
}, []);

const animHeaderHeight = runTiming(
clock,
keyboardShown,
animContentHeight,
animKeyboardHeight
);

return (
<SafeAreaView style={styles.container}>
<KeyboardAvoidingView style={styles.container} behavior="padding">
<View style={styles.header}>
<Text style={styles.headerText}>Header</Text>
</View>
<Animated.View
style={[styles.animatedSpace, { height: animHeaderHeight }]}
/>
<View onLayout={handleLayout}>
<View style={styles.heading}>
<Text style={styles.headingText}>
Note: CHANGE THIS TEXT CONTENT TO WHATEVER LENGTH MAKES THE BOTTOM
BUTTON OVERLAP THE TEXT INPUT WHEN THE KEYBOARD IS SHOWN! Lorem
ipsum dolor sit amet, consectetur adipiscing elit.
</Text>
</View>
<View style={styles.textInputContainer}>
<TextInput style={styles.textInput} autoFocus={true} />
</View>
</View>
<TouchableOpacity style={styles.bottomButton} />
</KeyboardAvoidingView>
</SafeAreaView>
);
};

function runTiming(
clock,
keyboardShown,
animContentHeight,
animKeyboardHeight
) {
const state = {
finished: new Value(0),
position: new Value(0),
time: new Value(0),
frameTime: new Value(0)
};

const config = {
duration: 300,
toValue: new Value(-1),
easing: KEYBOARD_EASING
};

const upperContentHeightNode = add(
STATUS_BAR_HEIGHT,
HEADER_HEIGHT,
MAX_ANIMATED_HEIGHT,
animContentHeight
);
const keyboardContentHeightNode = add(
BOTTOM_BUTTON_HEIGHT,
animKeyboardHeight
);
const overlap = max(
sub(add(upperContentHeightNode, keyboardContentHeightNode), DEVICE_HEIGHT),
0
);
const headerMinHeightNode = max(sub(MAX_ANIMATED_HEIGHT, overlap), 0);

return block([
cond(and(eq(keyboardShown, 1), neq(config.toValue, 1)), [
set(state.finished, 0),
set(state.time, 0),
set(state.frameTime, 0),
set(config.toValue, 1),
startClock(clock)
]),
cond(and(eq(keyboardShown, 0), neq(config.toValue, 0)), [
set(state.finished, 0),
set(state.time, 0),
set(state.frameTime, 0),
set(config.toValue, 0),
startClock(clock)
]),
timing(clock, state, config),
cond(state.finished, stopClock(clock)),
interpolate(state.position, {
inputRange: [0, 1],
outputRange: [MAX_ANIMATED_HEIGHT, headerMinHeightNode]
})
]);
}

// Coloring below is used just to easily see the different components
const styles = StyleSheet.create({
container: {
flex: 1
},
header: {
height: HEADER_HEIGHT,
width: "100%",
backgroundColor: "teal",
justifyContent: "center",
alignItems: "center"
},
headerText: {
color: "white"
},
heading: {
alignItems: "center",
marginBottom: 15,
paddingHorizontal: 30
},
headingText: {
fontSize: 28,
fontWeight: "600",
textAlign: "center"
},
animatedSpace: {
backgroundColor: "pink",
width: "100%"
},
textInputContainer: {
alignItems: "center",
paddingHorizontal: 40,
width: "100%",
height: 60
},
textInput: {
backgroundColor: "lightgray",
width: "100%",
height: 60
},
bottomButton: {
marginTop: "auto",
height: BOTTOM_BUTTON_HEIGHT,
backgroundColor: "orange",
paddingHorizontal: 20
}
});

最终想法

我希望 UI fps 保持一致的 60,但是我的设置方式中的某些内容导致了帧丢失。我想知道这是否与我的 react-native-reanimated 动画依赖于键盘的状态(即依赖于来自 JS 线程的信息)这一事实有关。我有点想知道如果 JS 和 UI 线程之间没有通过桥接器进行持续通信,是否可以做到这一点。任何帮助或指导将不胜感激。

最佳答案

为了安全起见,您能否将 runTiming 调用包装到具有适当依赖项的用例中? [显示键盘等]。您的代码片段中有很多副作用可能会引发问题。

关于javascript - 如何在 React Native Reanimated 中对键盘事件使用react?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58418470/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com