I have a MainFooter
components that contains the footer and mini player which animates to full-view when clicked. I have a problem that whenever we click on one of the footer Tabs, the player maximizes and then got stuck there only, being unresponsive.
Also the down arrow icon inside player when clicked do not minimizes it, neither clicking on MiniPlayer maximizes it, but we can maximizes MiniPlayer by clicking and dragging it to full-view and same for maximized Player.
Here is the MainFooter
component:
export const MainFooter = ({ setCounter, counter }: Props) => {
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,
value: translationY,
velocity: velocityY,
snapPoints: [SNAP_TOP, SNAP_BOTTOM],
config,
}),
SNAP_TOP,
SNAP_BOTTOM
);
const translateY_ = withSpring({
value: clamp(translationY, SNAP_TOP, SNAP_BOTTOM),
velocity: velocityY,
offset,
state,
snapPoints: [SNAP_TOP, SNAP_BOTTOM],
config,
});
const translateBottomTab = interpolate(translateY, {
inputRange: [SNAP_BOTTOM - TABBAR_HEIGHT, 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,
});
return (
<>
<PanGestureHandler {...gestureHandler}>
<Animated.View
style={[
styles.playerSheet,
{ transform: [{ translateY: translateY }] },
]}
>
<Player
onPress={() => {
goDown.setValue(1);
console.log('player pressed!');
}}
/>
<Animated.View
pointerEvents='none'
style={{
opacity: opacity2,
backgroundColor: '#e0e0e0',
...StyleSheet.absoluteFillObject,
}}
/>
<Animated.View
style={{
opacity,
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: MINIMIZED_PLAYER_HEIGHT,
}}
>
<MiniPlayer
onPress={() => {
console.log('mini player pressed!');
goUp.setValue(1);
}}
/>
</Animated.View>
</Animated.View>
</PanGestureHandler>
<Animated.View
style={{ transform: [{ translateY: translateBottomTab }] }}
>
<FooterTabsContainer counter={counter} setCounter={setCounter} />
</Animated.View>
</>
);
};
const styles = StyleSheet.create({
playerSheet: {
...StyleSheet.absoluteFillObject,
backgroundColor: '#e0e0e0',
},
container: {
// backgroundColor: '#e0e0e0',
// position: 'absolute',
// bottom: 0,
// left: 0,
// right: 0,
// height: TABBAR_HEIGHT,
// flexDirection: 'row',
// borderTopColor: 'black',
// borderWidth: 1,
height: 'auto',
},
});
And here is the FooterTabsContainer
component:
const FooterTabsContainer = ({ counter, setCounter }: Props) => {
const tintColor = {
homeIcon: counter === 0 ? '#FFBC00' : '#555',
playIcon: counter === 1 ? '#FFBC00' : '#555',
loveIcon: counter === 2 ? '#FFBC00' : '#555',
profileIcon: counter === 3 ? '#FFBC00' : '#555',
};
return (
<>
<Footer>
<FooterTab style={styles.footerTab}>
<Button onPress={() => setCounter(0)}>
<Image
source={homeIcon}
style={{ ...styles.footerIcon, tintColor: tintColor.homeIcon }}
/>
</Button>
<Button onPress={() => setCounter(1)}>
<Image
source={playIcon}
style={{ ...styles.footerIcon, tintColor: tintColor.playIcon }}
/>
</Button>
<Button onPress={() => setCounter(2)}>
<Image
source={loveIcon}
style={{ ...styles.footerIcon, tintColor: tintColor.loveIcon }}
/>
</Button>
<Button
onPress={() => {
setCounter(3);
console.log('profile icon clicked!');
}}
>
<Image
source={profileIcon}
style={{ ...styles.footerIcon, tintColor: tintColor.profileIcon }}
/>
</Button>
</FooterTab>
</Footer>
</>
);
};
export default FooterTabsContainer;
const styles = StyleSheet.create({
footerTab: {
backgroundColor: '#FFF',
borderWidth: 2,
borderColor: '#f0f0f0',
},
footerIcon: {
width: 25,
height: 25,
},
});
I will appreciate any help or comments as to why this is happening in case of:
I am using "react-native-reanimated": "^1.13.2"
, "react-native-redash": "^8.0.0"
, "native-base": "^2.15.2"
, "react": "16.13.1", "react-native": "^0.64.0",
and "react-native-gesture-handler": "^1.9.0"
Maximized Player
Miniplayer:
It was because storing animated values as new values, so whenever; migrated to another footer Tab, the states were lost due to re-render, and the player was coming back to it's original state (up). TO fix this wrap animation values inside useRef()
and then use them:
const translationY = useRef(new Value(0));
const velocityY = useRef(new Value(0));
const state = useRef(new Value(State.UNDETERMINED));
const offset = new Value(SNAP_BOTTOM);
const goUp: React.MutableRefObject<Animated.Value<0 | 1>> = useRef(
new Value(0)
);
const goDown: React.MutableRefObject<Animated.Value<0 | 1>> = useRef(
new Value(0)
);
.
.
.
const translateY = useRef(
clamp(
withSpring({
state: state.current,
value: translationY.current,
velocity: velocityY.current,
offset,
snapPoints: [SNAP_TOP, SNAP_BOTTOM],
config,
}),
SNAP_TOP,
SNAP_BOTTOM
)
);