Mindinventory/react-native-tabbar-interaction

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",
},
});
`