Skip to content

Commit

Permalink
chore: implement initial animated tab bar
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhom committed Mar 18, 2020
1 parent 0afbf35 commit 1b05a9c
Show file tree
Hide file tree
Showing 11 changed files with 506 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
100 changes: 95 additions & 5 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,108 @@
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import AnimatedTabBar from '@gorhom/animated-tabbar';
import DummyScreen from './screens/DummyScreen';
import HomeSVG from './svg/HomeSVG';
import LikeSVG from './svg/LikeSVG';
import SearchSVG from './svg/SearchSVG';
import ProfileSVG from './svg/ProfileSVG';

const tabOptions = {
Home: {
labelStyle: {
color: '#5B37B7',
},
icon: {
component: HomeSVG,
activeColor: 'rgba(91,55,183,1)',
inactiveColor: 'rgba(0,0,0,1)',
},
background: {
activeColor: 'rgba(223,215,243,1)',
inactiveColor: 'rgba(223,215,243,0)',
},
},
Likes: {
labelStyle: {
color: '#C9379D',
},
icon: {
component: LikeSVG,
activeColor: 'rgba(201,55,157,1)',
inactiveColor: 'rgba(0,0,0,1)',
},
background: {
activeColor: 'rgba(247,215,243,1)',
inactiveColor: 'rgba(247,215,243,0)',
},
},
Search: {
labelStyle: {
color: '#E6A919',
},
icon: {
component: SearchSVG,
activeColor: 'rgba(230,169,25,1)',
inactiveColor: 'rgba(0,0,0,1)',
},
background: {
activeColor: 'rgba(251,239,211,1)',
inactiveColor: 'rgba(251,239,211,0)',
},
},
Profile: {
labelStyle: {
color: '#1194AA',
},
icon: {
component: ProfileSVG,
activeColor: 'rgba(17,148,170,1)',
inactiveColor: 'rgba(0,0,0,1)',
},
background: {
activeColor: 'rgba(207,235,239,1)',
inactiveColor: 'rgba(207,235,239,0)',
},
},
};

const Tab = createBottomTabNavigator();

export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={DummyScreen} />
<Tab.Screen name="Likes" component={DummyScreen} />
<Tab.Screen name="Search" component={DummyScreen} />
<Tab.Screen name="Profile" component={DummyScreen} />
<Tab.Navigator
tabBar={props => <AnimatedTabBar configs={tabOptions} {...props} />}
>
<Tab.Screen
name="Home"
initialParams={{
backgroundColor: tabOptions.Home.labelStyle.color,
}}
component={DummyScreen}
/>
<Tab.Screen
name="Likes"
initialParams={{
backgroundColor: tabOptions.Likes.labelStyle.color,
}}
component={DummyScreen}
/>
<Tab.Screen
name="Search"
initialParams={{
backgroundColor: tabOptions.Search.labelStyle.color,
}}
component={DummyScreen}
/>
<Tab.Screen
name="Profile"
initialParams={{
backgroundColor: tabOptions.Profile.labelStyle.color,
}}
component={DummyScreen}
/>
</Tab.Navigator>
</NavigationContainer>
);
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,17 @@
"bootstrap": "yarn example && yarn && yarn pods"
},
"dependencies": {
"react-native-redash": "^10.0.1"
"react-native-redash": "^10.0.1",
"use-memo-one": "^1.1.1"
},
"devDependencies": {
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"@react-native-community/bob": "^0.10.0",
"@react-native-community/eslint-config": "^0.0.7",
"@react-navigation/bottom-tabs": "^5.1.1",
"@react-navigation/native": "^5.0.9",
"@react-navigation/stack": "^5.1.1",
"@react-native-community/bob": "^0.10.0",
"@react-native-community/eslint-config": "^0.0.7",
"@release-it/conventional-changelog": "^1.1.0",
"@types/react": "^16.9.19",
"@types/react-native": "0.61.10",
Expand All @@ -60,8 +61,8 @@
"react": "~16.9.0",
"react-native": "~0.61.5",
"react-native-gesture-handler": "^1.6.0",
"react-native-safe-area-context": "^0.7.3",
"react-native-reanimated": "^1.7.0",
"react-native-safe-area-context": "^0.7.3",
"react-native-svg": "^12.0.3",
"release-it": "^13.1.1",
"typescript": "^3.8.3"
Expand Down
98 changes: 98 additions & 0 deletions src/AnimatedTabBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useCallback, useMemo } from 'react';
import Animated from 'react-native-reanimated';
import { useSafeArea } from 'react-native-safe-area-context';
import { CommonActions } from '@react-navigation/native';
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import { AnimatedTabBarItem } from './item';
import { styles } from './styles';
import { View } from 'react-native';

Animated.addWhitelistedNativeProps({
width: true,
stroke: true,
backgroundColor: true,
});

interface AnimatedTabBarProps extends BottomTabBarProps {
configs: any;
}

export const AnimatedTabBar = (props: AnimatedTabBarProps) => {
// props
const { state, navigation, descriptors, configs } = props;
const { routes } = state;

// variables
const safeArea = useSafeArea();

// styles
const containerStyle = useMemo(
() => [
styles.container,
{
paddingBottom: safeArea.bottom,
},
],
[safeArea]
);

// callbacks
const handleItemPress = useCallback(
(name, key, focused) => () => {
const event = navigation.emit({
type: 'tabPress',
target: key,
canPreventDefault: true,
});

if (!focused && !event.defaultPrevented) {
navigation.dispatch({
...CommonActions.navigate(name),
target: state.key,
});
}
},
[navigation, state]
);

const handleItemLongPress = useCallback(
key => () => {
navigation.emit({
type: 'tabLongPress',
target: key,
});
},
[navigation]
);

// render
return (
<View style={containerStyle}>
{routes.map((route, index) => {
const focused = index === state.index;
const { options } = descriptors[route.key];
const tabConfigs = configs[route.name];
const label = options.title !== undefined ? options.title : route.name;
const accessibilityLabel =
options.tabBarAccessibilityLabel !== undefined
? options.tabBarAccessibilityLabel
: typeof label === 'string'
? `${label}, tab, ${index + 1} of ${routes.length}`
: undefined;

return (
<AnimatedTabBarItem
key={route.key}
configs={tabConfigs}
focused={focused}
label={label}
accessibilityLabel={accessibilityLabel}
testID={options.tabBarTestID}
onPress={handleItemPress(route.name, route.key, focused)}
onLongPress={handleItemLongPress(route.key)}
/>
);
})}
</View>
);
};
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { AnimatedTabBar } from './AnimatedTabBar';
export { TabConfig } from './types';

export default AnimatedTabBar;
Loading

0 comments on commit 1b05a9c

Please sign in to comment.