我已按照本教程https://reactnavigation.org/docs/bottom-tab-navigator#tabbar使用react native导航创建了自定义标签栏组件。然后,我在导航顶部放置了一个自定义组件,以模仿Spotify最小化播放器,以便在我可以执行从最小化播放器到全尺寸播放器的拖动手势时。但是,当我运行该应用程序时,该手势在第一个屏幕上效果很好,但是当我切换屏幕时,该手势不起作用https://www.youtube.com/watch?v=w-8NSQyWPHI&feature=youtu.be。
import React, { Fragment, useState } from 'react';
import { Text, View, TouchableOpacity, Dimensions, StyleSheet } from 'react-native'
import { PanGestureHandler, State } from 'react-native-gesture-handler'
import { clamp, onGestureEvent, timing, withSpring } from 'react-native-redash'
import Animated from 'react-native-reanimated'
import { getBottomSpace } from 'react-native-iphone-x-helper'
import Player from './player/Player'
import MiniPlayer from './player/MiniPlayer'
const { height } = Dimensions.get('window')
const TABBAR_HEIGHT = getBottomSpace() + 50
const MINIMIZED_PLAYER_HEIGHT = 52
const SNAP_TOP = 0
const SNAP_BOTTOM = height - TABBAR_HEIGHT - MINIMIZED_PLAYER_HEIGHT
const config = {
damping: 30,
mass: 1,
stiffness: 150,
overshootClamping: false,
restSpeedThreshold: 0.1,
restDisplacementThreshold: 0.1
}
const {
Clock,
Value,
cond,
useCode,
set,
block,
not,
clockRunning,
interpolate,
diffClamp,
Extrapolate
} = Animated
const styles = StyleSheet.create({
container: {
flex: 1,
},
playerSheet: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'white'
}
})
export default ({ statee, descriptors, navigation }) => {
const translationY = new Value(0)
const velocityY = new Value(0)
const state = new Value(State.UNDETERMINED)
const offset = new Value(SNAP_BOTTOM)
const goUp: Animated.Value<0 | 1> = new Value(0)
const goDown: Animated.Value<0 | 1> = new Value(0)
const gestureHandler = onGestureEvent({
state,
translationY,
velocityY
})
const translateY = clamp(
withSpring({
state,
offset,
value: translationY,
velocity: velocityY,
snapPoints: [SNAP_TOP, SNAP_BOTTOM],
config
}),
SNAP_TOP,
SNAP_BOTTOM
)
const translateBottomTab = interpolate(translateY, {
inputRange: [SNAP_TOP, SNAP_BOTTOM],
outputRange: [TABBAR_HEIGHT, 0],
extrapolate: Extrapolate.CLAMP
})
const opacity = interpolate(translateY, {
inputRange: [SNAP_BOTTOM - MINIMIZED_PLAYER_HEIGHT, SNAP_BOTTOM],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP
})
const opacity2 = interpolate(translateY, {
inputRange: [
SNAP_BOTTOM - MINIMIZED_PLAYER_HEIGHT * 2,
SNAP_BOTTOM - MINIMIZED_PLAYER_HEIGHT
],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP
})
const clock = new Clock()
useCode(
block([
cond(goUp, [
set(
offset,
timing({
clock,
from: offset,
to: SNAP_TOP
})
),
cond(not(clockRunning(clock)), [set(goUp, 0)])
]),
cond(goDown, [
set(
offset,
timing({
clock,
from: offset,
to: SNAP_BOTTOM
})
),
cond(not(clockRunning(clock)), [set(goDown, 0)])
])
]),
[]
)
goUpHandler = () => {
console.log('TAPPERD UP');
goUp.setValue(1)
}
goDownHandler = () => {
console.log('TAPPERD DOWN');
goDown.setValue(1)
}
return (
<>
<PanGestureHandler {...gestureHandler}>
<Animated.View
style={[styles.playerSheet, { transform: [{ translateY }] }]}
>
<Player onPress={this.goDownHandler} />
<Animated.View
pointerEvents='none'
style={{
opacity: opacity2,
backgroundColor: 'white',
...StyleSheet.absoluteFillObject
}}
/>
<Animated.View style={{
opacity: opacity,
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: MINIMIZED_PLAYER_HEIGHT
}}>
<MiniPlayer onPress={this.goUpHandler} />
</Animated.View>
</Animated.View>
</PanGestureHandler>
<Animated.View style={{
flexDirection: 'row',
height: TABBAR_HEIGHT,
paddingTop: 8,
justifyContent: 'center',
backgroundColor: 'white',
transform: [{ translateY: translateBottomTab }]
}}>
{statee.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const Icon = options.tabBarIcon
const isFocused = statee.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
return (
<Animated.View style={styles.container} key={index}>
<Animated.View style={{
alignItems: 'center',
justifyContent: 'center'
}}>
<TouchableOpacity
accessibilityRole="button"
accessibilityStates={isFocused ? ['selected'] : []}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
>
<Icon />
</TouchableOpacity>
</Animated.View>
</Animated.View>
);
})}
</Animated.View>
</>
);
}
答案 0 :(得分:0)
我有确切的问题。这是因为reanimated
在重新渲染时被弄乱了。
我通过将以下代码移出功能/类组件使其全局来解决此问题。
const translationY = new Value(0)
const velocityY = new Value(0)
const state = new Value(State.UNDETERMINED)
const offset = new Value(SNAP_BOTTOM)
const goUp: Animated.Value<0 | 1> = new Value(0)
const goDown: Animated.Value<0 | 1> = new Value(0)
const gestureHandler = onGestureEvent({
state,
translationY,
velocityY
})
const translateY = clamp(
withSpring({
state,
offset,
value: translationY,
velocity: velocityY,
snapPoints: [SNAP_TOP, SNAP_BOTTOM],
config
}),
SNAP_TOP,
SNAP_BOTTOM
)
const translateBottomTab = interpolate(translateY, {
inputRange: [SNAP_TOP, SNAP_BOTTOM],
outputRange: [TABBAR_HEIGHT, 0],
extrapolate: Extrapolate.CLAMP
})
const opacity = interpolate(translateY, {
inputRange: [SNAP_BOTTOM - MINIMIZED_PLAYER_HEIGHT, SNAP_BOTTOM],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP
})
const opacity2 = interpolate(translateY, {
inputRange: [
SNAP_BOTTOM - MINIMIZED_PLAYER_HEIGHT * 2,
SNAP_BOTTOM - MINIMIZED_PLAYER_HEIGHT
],
outputRange: [0, 1],
extrapolate: Extrapolate.CLAMP
})
const clock = new Clock()
useCode(
block([
cond(goUp, [
set(
offset,
timing({
clock,
from: offset,
to: SNAP_TOP
})
),
cond(not(clockRunning(clock)), [set(goUp, 0)])
]),
cond(goDown, [
set(
offset,
timing({
clock,
from: offset,
to: SNAP_BOTTOM
})
),
cond(not(clockRunning(clock)), [set(goDown, 0)])
])
]),
[]
)