React-native-tab-view: Change text color on change of tab?

Created on 5 May 2017  ·  16Comments  ·  Source: satya164/react-native-tab-view

is there any method to change the tab text color on change of tab.Right now its just lighten the text color but wanted to change it to a different color ?

All 16 comments

https://github.com/react-native-community/react-native-tab-view/blob/master/example/src/ScrollViewsExample.js#L63

You highlighted string number 63 "this._third.scrollTo({ y: 0 });" but how does this relate to change text color of a tab (сhange to a color different from the original, not just lighten)?

Example:
2

Please read the full example.

@valeriik Were you able to make sense of the example? I'm also trying to change the style of the tab label itself when it is selected.

@andrewcroce for now I did not try and I cannot realize how @satya164's answer can help me :)

@satya164's example work! now I understand how to change text color when changing tab thanks!

@1c7 can you please explain?

@karimkhamwani ah, it's too long now, I forgot

@1c7 awww please help. paste your code i will figure it out

@karimkhamwani

Code example for "Change text color on change of tab? "

  • Hope this help, I copy entire file.
  • File path: project_name/src/MainScreen.js
  • React Native 0.52, build mainly for Android
  • just ignore the part you don't need(i18n, other screen, load config, MobX, etc)
    focus on how to change color when changing tab
  • if it work, let me know :)
import * as React from 'react'
import { Animated, View, TouchableWithoutFeedback, StyleSheet, Text, AsyncStorage, Dimensions, Alert, ToastAndroid } from 'react-native'
import { TabViewAnimated } from 'react-native-tab-view'
import Config from '../src/config'
import API from '../src/API'
import HomeScreen from './HomeScreen' 
import LogsScreen from './LogsScreen'    
import ProfileScreen from './ProfileScreen';  
import BigjpgStore from '../src/BigjpgStore.js'
import I18n from '../i18n/i18n'
import DeviceInfo from 'react-native-device-info'
import {fetch_bigjpg, load_app_config } from './utils'
import ReactNativeLanguages from 'react-native-languages';
import { I18nextProvider, translate } from 'react-i18next';

class MainScreen extends React.Component {
  componentWillMount() {
    ReactNativeLanguages.addEventListener('change', this._onLanguagesChange);
  }

  componentWillUnmount() {
    ReactNativeLanguages.removeEventListener('change', this._onLanguagesChange);
  }

  _onLanguagesChange = ({ language, languages }) => {
    I18n.changeLanguage(language);
  };

  constructor(props) {
    super(props);
    AsyncStorage.getItem('logs').then((value) => {
      if (value != '' && value != null) {
        BigjpgStore.logs = JSON.parse(value);
      }
    }).catch((err) => {});
    this._handleIndexChange = this._handleIndexChange.bind(this);
    this.state = {
      index: 0,
      routes: [
        { key: '1', title: I18n.t('begin'), light: require('../assets/index.png'), dark: require('../assets/index-h.png'), navigation: this.props.navigation },
        { key: '2', title: I18n.t('log'), light: require('../assets/logs.png'), dark: require('../assets/logs-h.png'), navigation: this.props.navigation, jump: this.jump.bind(this) },
        { key: '3', title: I18n.t('conf'), light: require('../assets/conf.png'), dark: require('../assets/conf-h.png'), navigation: this.props.navigation },
      ],
      change: 1,
    };

    // I have to do this, otherwise when switch language, the text wouldn't change
    setInterval(()=>{
      this.setState({
        routes: [
          { key: '1', title: I18n.t('begin'), light: require('../assets/index.png'), dark: require('../assets/index-h.png'), navigation: this.props.navigation },
          { key: '2', title: I18n.t('log'), light: require('../assets/logs.png'), dark: require('../assets/logs-h.png'), navigation: this.props.navigation, jump: this.jump.bind(this) },
          { key: '3', title: I18n.t('conf'), light: require('../assets/conf.png'), dark: require('../assets/conf-h.png'), navigation: this.props.navigation },
        ]
      });
    },3000)
  }
  componentDidMount() {
    load_app_config();
  }

  static navigationOptions = ({ navigation }) => ({
    headerVisible: false,
    headerMode: 'none',
    header: null,
  });

  _handleIndexChange(index){
    this.setState({ index }, ()=>{
      if (index == 1 || index == 2) {
        if (BigjpgStore.is_login) {
          setTimeout(()=>{
            BigjpgStore.get_user_info();
          },100);
        }
      }
    });
  }

  _renderLabel = ({ position, navigationState }) => ({ route, index }) => {
    const inputRange = navigationState.routes.map((x, i) => i);
    const outputRange = inputRange.map(
      inputIndex => (inputIndex === index ? '#000' : '#c9ced6')
    );
    const color = position.interpolate({
      inputRange,
      outputRange,
    });
    return (
      <Animated.Text style={[styles.label, { color }]}>
        {route.title}
      </Animated.Text>
    );
  };

  _renderIcon = ({ navigationState, position }) => ({ route, index }) => {
    const inputRange = navigationState.routes.map((x, i) => i);
    const filledOpacity = position.interpolate({
      inputRange,
      outputRange: inputRange.map(i => (i === index ? 1 : 0)),
    });
    const outlineOpacity = position.interpolate({
      inputRange,
      outputRange: inputRange.map(i => (i === index ? 0 : 1)),
    });
    return (
      <View style={styles.iconContainer}>
        <Animated.Image
          style={[
            { width: 28, height: 28 },
            styles.icon, { opacity: filledOpacity }
          ]}
          source={route.dark}
        />
        <Animated.Image
          style={[
            { width: 28, height: 28 },
            styles.icon, { opacity: outlineOpacity }
          ]}
          source={route.light}
        />
      </View>
    );
  };

  _renderFooter = props => (
    <View style={styles.tabbar}>
      {props.navigationState.routes.map((route, index) => {
        return (
          <TouchableWithoutFeedback key={route.key} onPress={() => props.jumpToIndex(index)}>
            <Animated.View style={styles.tab}>
              {this._renderIcon(props)({ route, index })}
              {this._renderLabel(props)({ route, index })}
            </Animated.View>
          </TouchableWithoutFeedback>
        );
      })}
    </View>
  );

  jump(index) {
    this.setState({
      index: index
    })
  }

  _renderScene({ route }) {
    const n = route.navigation;
    switch (route.key) {
      case '1':
        return (
          <HomeScreen navigation={n} />
        );
      case '2':
        return (
          <LogsScreen navigation={n} jump={route.jump} />
        );
      case '3':
        return (
          <ProfileScreen navigation={n} />
        );
      default:
        return null;
    }
  };

  render() {
    const { navigate } = this.props.navigation;
    return (
      <I18nextProvider i18n={I18n}>
        <TabViewAnimated
          style={[styles.container, this.props.style]}
          navigationState={this.state}
          renderScene={this._renderScene}
          renderFooter={this._renderFooter}
          animationEnabled={true}
          swipeEnabled={true}
          onIndexChange={this._handleIndexChange}
        />
      </I18nextProvider>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  tabbar: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    backgroundColor: '#f4f4f4',
  },
  tab: {
    flex: 1,
    alignItems: 'center',
    borderTopWidth: StyleSheet.hairlineWidth,
    borderTopColor: 'rgba(0, 0, 0, .2)',
    paddingTop: 4.5,
  },
  iconContainer: {
    height: 26,
    width: 26,
  },
  icon: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
  },
  label: {
    fontSize: 10,
    marginTop: 3,
    marginBottom: 1.5,
    backgroundColor: 'transparent',
  },
});

export default MainScreen;

this is the key part

  _renderLabel = ({ position, navigationState }) => ({ route, index }) => {
    const inputRange = navigationState.routes.map((x, i) => i);
    const outputRange = inputRange.map(
      inputIndex => (inputIndex === index ? '#000' : '#c9ced6')
    );
    const color = position.interpolate({
      inputRange,
      outputRange,
    });
    return (
      <Animated.Text style={[styles.label, { color }]}>
        {route.title}
      </Animated.Text>
    );
  };

Thanks

@karimkhamwani you are welcome

https://github.com/react-native-community/react-native-tab-view/blob/master/example/src/ScrollViewsExample.js#L63

You highlighted string number 63 "this._third.scrollTo({ y: 0 });" but how does this relate to change text color of a tab (сhange to a color different from the original, not just lighten)?

Example:
2

try this one:

import  *  as  React  from  "react";
import { Dimensions, Animated, TouchableOpacity,View } from  "react-native";
import { TabView, SceneMap } from  "react-native-tab-view";

const FirstRoute = () => (<View style={[styles.scene, { backgroundColor: "#ff4081" }]} />);
const SecondRoute = () => (<View style={[styles.scene, { backgroundColor: "#673ab7" }]} />);

class TopBar extends React.Component<Props, State> {
    state = {
        index: 1,
        routes: [
            { key: "first", title: "First" },
            { key: "second", title: "Second" },
        ],
    };



_getTabWidth = props => {
        return props.layout.width / props.navigationState.routes.length;
    }
    _renderIndicator = props => {
        const { width, position, navigationState } = props;
        const translateX = Animated.multiply(
            Animated.multiply(
                position.interpolate({
                    inputRange: [0, navigationState.routes.length - 1],
                    outputRange: [0, navigationState.routes.length - 1],
                    extrapolate: "clamp",
                }),
                width,
            ),
            1,
        );
        return (
            <Animated.View
                style={[
                    styles.indicator,
                    {
                        width,
                        transform: [{ translateX }],
                        backgroundColor: "#673ab7",
                        height: 5,
                    },
                ]}
            />
        );
    }
    _renderTabBar = props => {
        const inputRange = props.navigationState.routes.map(({}, i) => i);
        const tabWidth = this._getTabWidth(props);
        return (
            <View style={styles.tabBar}>
                <Animated.View pointerEvents="none" style={[styles.indicatorContainer]}>
                    {this._renderIndicator({
                        ...props,
                        width: tabWidth,
                    })}
                </Animated.View>
                {props.navigationState.routes.map((route, i) => {
                    const color = props.position.interpolate({
                        inputRange,
                        outputRange: inputRange.map(inputIndex =>
                            inputIndex === i ? "#D6356C" : "#222",
                        ),
                    });
                    return (
                        <TouchableOpacity
                            style={styles.tabItem}
                            onPress={() => this.setState({ index: i })}
                        >
                            <Animated.Text style={{ color }}>{route.title}</Animated.Text>
                        </TouchableOpacity>
                    );
                })}
            </View>
        );
    }

    render() {
        return (
            <TabView
                navigationState={this.state}
                renderScene={SceneMap({
                    first: FirstRoute,
                    second: SecondRoute,
                })}
                onIndexChange={index => this.setState({ index })}
                initialLayout={{
                    width: Dimensions.get("window").width,
                    height: 0,
                }}
                renderTabBar={this._renderTabBar}
            />
        );
    }
}

const styles = StyleSheet.create({
scene: {

flex: 1,

},
  tabBar: {
        flexDirection: "row",
    },
tabItem: {
        flex: 1,
        alignItems: "center",
        padding: 16,
    }
    indicatorContainer: {
        position: "absolute",
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
    },
    indicator: {
        backgroundColor: "#ffeb3b",
        position: "absolute",
        left: 0,
        bottom: 0,
        right: 0,
        height: 2,
    }
});
export  default  TopBar;

const color = position.interpolate({
inputRange,
outputRange,
});

some one please help . position.interpolate is showing error undefined is not a function

Ok got the solution by this way

_renderLabel = props => ({ route,focused, index }) => {
const inputRange = props.navigationState.routes.map((x, i) => i);
const color = focused ? '#c94b4b':'#000000'

return (
  <Animated.Text style={[{ fontSize: 14,fontFamily: 'Lato-Regular'}, { color }]}>
    {route.title}
  </Animated.Text>
);

};

Was this page helpful?
0 / 5 - 0 ratings

Related issues

compojoom picture compojoom  ·  4Comments

AndriiUhryn picture AndriiUhryn  ·  3Comments

KingAmo picture KingAmo  ·  3Comments

jasonkw9 picture jasonkw9  ·  3Comments

hyochan35 picture hyochan35  ·  3Comments