Change active tab
RedirexStudio opened this issue ยท 4 comments
Hello! Thank you a lot for your job!
I have one question: How i can change active tab by default? Now default active slide is first, but i want change it on therty
@RedirexStudio current version is not supporting to mark any tab as the default selected tab.
we will include your suggestion in our next version.
Thanks for using this lib.
@RedirexStudio please try the latest version 2.2.2 for your request. we have added the option to set the default active tab.
Ooh, Thank you a lot! It's really helped me! You a very responsive team and it's great and i'll suggest your lib to all my friends!
By the way, if you interesting... I was try to hardcode it :D
I had try to change index active tab in this case )))
TabBar.tsx
`import * as React from "react";
import {
SafeAreaView,
StyleSheet,
Dimensions,
View,
Animated,
Text,
TextStyle,
} from "react-native";
import * as shape from "d3-shape";
import Svg, { Path } from "react-native-svg";
import StaticTabbar from "./StaticTabbar";
const AnimatedSvg = Animated.createAnimatedComponent(Svg);
let { width } = Dimensions.get("window");
const height = 65;
const getPath = (tabWidth: number, width: number) => {
const left = shape
.line()
.x((d) => d.x)
.y((d) => d.y)([
{ x: 0, y: 0 },
{ x: width + tabWidth / 2, y: 0 },
]);
const tab = shape
.line()
.x((d) => d.x)
.y((d) => d.y)
.curve(shape.curveBasis)([
{ x: width + width / 2 - 100, y: 0 },
{ x: width + width / 2 - 65 + -35, y: 0 },
{ x: width + width / 2 - 50 + 10, y: -6 },
{ x: width + width / 2 - 50 + 15, y: height - 14 },
{ x: width + width / 2 + 50 - 15, y: height - 14 },
{ x: width + width / 2 + 50 - 10, y: -6 },
{ x: width + width / 2 + 65 - -35, y: 0 },
{ x: width + width / 2 + 100, y: 0 },
]);
const right = shape
.line()
.x((d) => d.x)
.y((d) => d.y)([
{ x: width, y: 0 },
{ x: width * 2, y: 0 },
{ x: width * 2, y: height },
{ x: 0, y: height },
{ x: 0, y: 0 },
]);
return ` ${tab} `;
};
export interface TabsType {
name: string;
title: string;
activeIcon: JSX.Element;
inactiveIcon: JSX.Element;
}
interface Props {
tabs: Array;
containerTopRightRadius?: number;
tabBarBackground: string;
tabBarContainerBackground: string;
containerBottomSpace?: number;
containerWidth?: number;
containerTopLeftRadius?: number;
containerBottomLeftRadius?: number;
containerBottomRightRadius?: number;
activeTabBackground?: string;
labelStyle?: TextStyle;
onTabChange?: (tab: TabsType) => void;
}
export default class Tabbar extends React.PureComponent {
value = new Animated.Value(2);
render() {
const {
tabs,
containerTopRightRadius,
tabBarBackground,
tabBarContainerBackground,
containerBottomSpace,
containerWidth,
containerTopLeftRadius,
containerBottomLeftRadius,
containerBottomRightRadius,
} = this.props;
let CustomWidth = containerWidth ? containerWidth : width;
const { value } = this;
const translateX = value.interpolate({
inputRange: [0, CustomWidth],
outputRange: [-CustomWidth, 0],
});
let tabBarBackgroundColor = tabBarBackground
? tabBarBackground
: "transparent";
const tabWidth: number | void | string =
tabs.length > 0
// ? CustomWidth / tabs.length
? CustomWidth
: console.error("please add tab data");
let d;
if (typeof tabWidth == "number") {
d = getPath(tabWidth, CustomWidth);
}
let borderTopRightRadius = containerTopRightRadius
? containerTopRightRadius
: 0;
let borderTopLeftRadius = containerTopLeftRadius
? containerTopLeftRadius
: 0;
let borderBottomLeftRadius = containerBottomLeftRadius
? containerBottomLeftRadius
: 0;
let borderBottomRightRadius = containerBottomRightRadius
? containerBottomRightRadius
: 0;
if (tabs.length > 0) {
return (
<>
<View
style={{
backgroundColor: tabBarContainerBackground
? tabBarContainerBackground
: "#fff",
position: "absolute",
bottom: containerBottomSpace ? containerBottomSpace : 0,
alignSelf: "center",
borderTopRightRadius,
borderTopLeftRadius,
borderBottomLeftRadius,
borderBottomRightRadius,
}}
>
<View
{...{
height,
width: CustomWidth,
backgroundColor: tabBarContainerBackground
? tabBarContainerBackground
: "#fff",
alignSelf: "center",
borderTopRightRadius,
borderTopLeftRadius,
borderBottomLeftRadius,
borderBottomRightRadius,
}}
>
<AnimatedSvg
width={CustomWidth * 2}
{...{ height }}
style={{
transform: [{ translateX }],
justifyContent: "center",
alignItems: "center",
}}
>
<Path fill={tabBarBackgroundColor} {...{ d }} />
</AnimatedSvg>
<View style={StyleSheet.absoluteFill}>
<StaticTabbar {...this.props} {...{ tabs, value }} />
</View>
</View>
<SafeAreaView
style={{
alignSelf: "center",
borderBottomLeftRadius,
borderBottomRightRadius,
}}
/>
</View>
</>
);
} else {
return (
<View style={styles.emptyContainer}>
<Text>Please add tab data</Text>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
width: width,
},
emptyContainer: { flex: 1, justifyContent: "center", alignItems: "center" },
});
`
StaticTabbar.tsx
`import * as React from "react";
import {
View,
StyleSheet,
TouchableWithoutFeedback,
Animated,
Dimensions,
Text,
TextStyle,
} from "react-native";
import { TabsType } from "./TabBar";
let { width } = Dimensions.get("window");
var prevIndex = -1;
interface Props {
value?: Animated.AnimatedValue;
tabs: Array;
onTabChange?: (tab: TabsType) => void;
labelStyle?: TextStyle;
activeTabBackground?: string;
Hvalue?: number;
containerWidth?: number;
}
export default class StaticTabbar extends React.PureComponent {
values: Array<Animated.AnimatedValue>;
constructor(props: Props) {
super(props);
const { tabs } = this.props;
this.values = tabs?.map(
(tab, index) => new Animated.Value(index === 2 ? 2 : 0)
);
}
onPress = (index: number) => {
if (prevIndex !== index) {
const { value, tabs, containerWidth } = this.props;
let customWidth = containerWidth ? containerWidth : width;
const tabWidth = customWidth / tabs.length;
Animated.sequence([
Animated.parallel(
this.values.map(
(v: Animated.AnimatedValue | Animated.AnimatedValueXY) =>
Animated.timing(v, {
toValue: 0,
duration: 50,
useNativeDriver: true,
})
)
),
Animated.timing(value, {
toValue: tabWidth * (index-2),
useNativeDriver: true,
}),
Animated.timing(this.values[index], {
toValue: 1,
useNativeDriver: true,
duration: 750,
}),
]).start();
prevIndex = index;
}
};
render() {
const { onPress } = this;
const {
tabs,
value,
activeTabBackground,
labelStyle,
onTabChange,
containerWidth,
} = this.props;
let customWidth = containerWidth ? containerWidth : width;
let mergeLabelStyle = { ...styles.labelStyle, ...labelStyle };
let newActiveIcon = [
styles.activeIcon,
{ backgroundColor: activeTabBackground ? activeTabBackground : "#fff" },
];
return (
{tabs.map((tab, key) => {
const tabWidth = customWidth / tabs.length;
const cursor = tabWidth * (key-2);
const opacity = value.interpolate({
inputRange: [cursor - tabWidth, cursor, cursor + tabWidth],
outputRange: [1, 0, 1],
extrapolate: "clamp",
});
const opacity1 = this.values[key].interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: "clamp",
});
return (
<React.Fragment {...{ key }}>
<TouchableWithoutFeedback
onPress={() => {
onPress(key);
onTabChange && onTabChange(tab);
}}
>
<Animated.View style={[styles.tab, { opacity, zIndex: 100 }]}>
{tab.inactiveIcon}
<Text style={mergeLabelStyle}>{tab.title}</Text>
</Animated.View>
</TouchableWithoutFeedback>
<Animated.View
style={{
position: "absolute",
top: -8,
left: tabWidth * key,
width: tabWidth,
height: 64,
justifyContent: "center",
alignItems: "center",
opacity: opacity1,
zIndex: 50,
}}
>
<View style={newActiveIcon}>{tab.activeIcon}</View>
</Animated.View>
</React.Fragment>
);
})}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
},
tab: {
flex: 1,
justifyContent: "center",
alignItems: "center",
height: 64,
},
activeIcon: {
width: 60,
height: 60,
borderRadius: 50,
marginBottom: 30,
justifyContent: "center",
alignItems: "center",
},
labelStyle: {
fontSize: 11,
fontWeight: "600",
// marginTop: 3,
color: "#000",
},
});
`