Giter VIP home page Giter VIP logo

react-native-underline-tabbar's Introduction

react-native-underline-tabbar

npm version code style: prettier

Custom Tabbar for https://github.com/skv-headless/react-native-scrollable-tab-view. It consists of some features e.g. scrollable content in tabs. Animations are build on matrix transformations and fully compatible with Animated library. In a new version there was significant improvement of tabbar behaviour.

Contribution

Issues are welcome. Please add a screenshot of bug and code snippet. Quickest way to solve issue is to reproduce it on one of the examples.

Pull requests are welcome. If you want to change API or making something big better to create issue and discuss it first. Before submiting PR please run eslint . Also all eslint fixes are welcome.

Please attach video or gif to PR's and issues it is super helpful.

Installation

npm install react-native-underline-tabbar --save
Or using Yarn
yarn add react-native-underline-tabbar

Showcase

react-native-underline-tabbar demo

Documentation

Property Type Default Description
tabs { label: string, badge:string, badgeColor?: string, [string]: any}[] required You don't have to pass this prop directly to tabbar. Istead, it's automatically passed from ScrollableTabView from tabLabel of your page. In defaultTabbar it is used only to pass a label, but we use it to pass there information about badges. Example tabLabel={{label: "Page #4", badge: 8, badgeColor: 'violet'}}. Also you can pass any data you need as it's used as Map
underlineColor string "navy" Set a color for underline. You can use also transparent to hide underline
underlineHeight number 2 Set a height for underline
underlineBottomPosition number 0 Set a bottom for underline
tabBarStyle Object {} Set styles to TabBar container
activeTabTextStyle Object {} Set styles to text in tabs while tab is active
tabBarTextStyle Object {} Set styles to text in tabs
tabBadgeColor string {} Set a common color for all badges. To set badgeColor individually use badgeColor in tab property
tabMargin number 20 Set space between tabs
tabStyles { tab?: Object, badgeBubble?: Object, badgeText?: Object } { tab: {}, badgeBubble: {}, badgeText: {} } Set styles for every tab and bubble
scrollContainerStyle Object {} Set styles for the scroll container

Simple Usage

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import TabBar from "react-native-underline-tabbar";

const Page = ({label}) => (
    <View style={styles.container}>
      <Text style={styles.welcome}>
        {label}
      </Text>
      <Text style={styles.instructions}>
        To get started, edit index.ios.js
      </Text>
      <Text style={styles.instructions}>
        Press Cmd+R to reload,{'\n'}
        Cmd+D or shake for dev menu
      </Text>
    </View>
);

class example extends Component {
  render() {
    return (
        <View style={[styles.container, {paddingTop: 20}]}>
          <ScrollableTabView
              tabBarActiveTextColor="#53ac49"
              renderTabBar={() => <TabBar underlineColor="#53ac49" />}>
            <Page tabLabel={{label: "Page #1"}} label="Page #1"/>
            <Page tabLabel={{label: "Page #2 aka Long!", badge: 3}} label="Page #2 aka Long!"/>
            <Page tabLabel={{label: "Page #3"}} label="Page #3"/>
            <Page tabLabel={{label: "Page #4 aka Page"}} label="Page #4 aka Page"/>
            <Page tabLabel={{label: "Page #5"}} label="Page #5"/>
          </ScrollableTabView>

        </View>
    );
  }
}

Advanced usage

import React, { Component } from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Animated } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import TabBar from 'react-native-underline-tabbar';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
    fontSize: 28,
  },
});

const Page = ({label, text = ''}) => (
  <View style={styles.container}>
    <Text style={styles.welcome}>
      {label}
    </Text>
    <Text style={styles.instructions}>
      {text}
    </Text>
  </View>
);

const iconsSet = {
  hot: require('./images/ic_whatshot.png'),
  trending: require('./images/ic_trending_up.png'),
  fresh: require('./images/ic_fiber_new.png'),
  funny: require('./images/ic_tag_faces.png'),
  movieAndTv: require('./images/ic_live_tv.png'),
  sport: require('./images/ic_rowing.png'),
};

const Tab = ({ tab, page, isTabActive, onPressHandler, onTabLayout, styles }) => {
  const { label, icon } = tab;
  const style = {
    marginHorizontal: 20,
    paddingVertical: 10,
  };
  const containerStyle = {
    paddingHorizontal: 20,
    paddingVertical: 5,
    borderRadius: 25,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: styles.backgroundColor,
    opacity: styles.opacity,
    transform: [{ scale: styles.opacity }],
  };
  const textStyle = {
    color: styles.textColor,
    fontWeight: '600',
  };
  const iconStyle = {
    tintColor: styles.textColor,
    resizeMode: 'contain',
    width: 22,
    height: 22,
    marginLeft: 10,
  };
  return (
    <TouchableOpacity style={style} onPress={onPressHandler} onLayout={onTabLayout} key={page}>
      <Animated.View style={containerStyle}>
        <Animated.Text style={textStyle}>{label}</Animated.Text>
        <Animated.Image style={iconStyle} source={icon} />
      </Animated.View>
    </TouchableOpacity>
  );
};

class UnderlineTabBarExample extends Component {
  _scrollX = new Animated.Value(0);
  // 6 is a quantity of tabs
  interpolators = Array.from({ length: 6 }, (_, i) => i).map(idx => ({
    scale: this._scrollX.interpolate({
      inputRange: [idx - 1, idx, idx + 1],
      outputRange: [1, 1.2, 1],
      extrapolate: 'clamp',
    }),
    opacity: this._scrollX.interpolate({
      inputRange: [idx - 1, idx, idx + 1],
      outputRange: [0.9, 1, 0.9],
      extrapolate: 'clamp',
    }),
    textColor: this._scrollX.interpolate({
      inputRange: [idx - 1, idx, idx + 1],
      outputRange: ['#000', '#fff', '#000'],
    }),
    backgroundColor: this._scrollX.interpolate({
      inputRange: [idx - 1, idx, idx + 1],
      outputRange: ['rgba(0,0,0,0.1)', '#000', 'rgba(0,0,0,0.1)'],
      extrapolate: 'clamp',
    }),
  }));
  render() {
    return (
      <View style={[styles.container, { paddingTop: 20 }]}>
        <ScrollableTabView
          renderTabBar={() => (
            <TabBar
              underlineColor="#000"
              tabBarStyle={{ backgroundColor: "#fff", borderTopColor: '#d2d2d2', borderTopWidth: 1 }}
              renderTab={(tab, page, isTabActive, onPressHandler, onTabLayout) => (
                <Tab
                  key={page}
                  tab={tab}
                  page={page}
                  isTabActive={isTabActive}
                  onPressHandler={onPressHandler}
                  onTabLayout={onTabLayout}
                  styles={this.interpolators[page]}
                />
              )}
            />
          )}
          onScroll={(x) => this._scrollX.setValue(x)}
        >
          <Page tabLabel={{label: "Hot", icon: iconsSet.hot}} label="Page #1 Hot" text="You can pass your own views to TabBar!"/>
          <Page tabLabel={{label: "Trending", icon: iconsSet.trending}} label="Page #2 Trending" text="Yehoo!!!"/>
          <Page tabLabel={{label: "Fresh", icon: iconsSet.fresh}} label="Page #3 Fresh" text="Hooray!"/>
          <Page tabLabel={{label: "Funny", icon: iconsSet.funny}} label="Page #4 Funny"/>
          <Page tabLabel={{label: "Movie & TV", icon: iconsSet.movieAndTv}} label="Page #5 Movie & TV"/>
          <Page tabLabel={{label: "Sport", icon: iconsSet.sport}} label="Page #6 Sport"/>
        </ScrollableTabView>
      </View>
    );
  }
}

Notice! In case of using this tabbar we must pass object into tabLabel property. It is necessary to set labels and badges.

Example

Example is here

Changelog

  • [1.3.6]
    • Improve recalculation of scroll values
  • [1.3.5]
    • Improve underline rerender on tab layout updates
    • Minor code improvments
  • [1.3.4]
    • Improve and update Advanced usage example
  • [1.3.3]
    • Improve initial setup with initialPage property
    • Remove shouldScroll parameter due to its non-ideal work
  • [1.3.2]
    • Update Readme
  • [1.3.1]
    • Describe tabStyles with flow
    • Add tab customization in documentation
    • Update Readme
  • [1.3.0]
    • Fix an error related to types export
  • [1.2.8]
    • Minor fix
  • [1.2.7]
    • Types are available for importing
  • [1.2.6]
    • Improve offset calculations for tabs which are located in the end of TabBar
    • Now you can pass more than 10 tabs to component
  • [1.2.5]
    • Fix bug when activeTabTextStyle had lower priority than just textStyle
    • Add customization for underline
  • [1.2.4]
    • Update descriptions.
  • [1.2.3]
    • Fixed bug when user provide less than two tabs.
  • [1.2.2]
    • Minor changes
  • [1.2.1]
    • Now it's possible to pass your own renderTab function (hooray!). It opens many opportunities for customization
    • Type of Tab has been changed. Now it's a map where you can pass any data you need to use in your custom Tab view
    • Example has been added
  • [1.2.0]
    • Initial setup now depends on initialPage prop.
    • Calculating of interpolations now doesn't apply transformations to underline. It prevents flickering when tab has styles which resize it
    • Better manual scrolling performance of TabBar
  • [1.1.7]
    • Possibly unnecessary transformations to underline have been removed. It improves behaviour on Android
  • [1.1.6]
    • Change hardcoded marginValue on value from props to calculate scroll positions properly
  • [1.1.5]
    • Prevent crashing on android devices
  • [1.1.4]
    • Interpolation values are calculated only when all mandatory views are measured. It prevents incorrect behaviour of tabs scrolling and underline.
    • Now you can set default colour for badges using tabBadgeColor prop
    • Now you can set margins between tabs using tabMargin prop

react-native-underline-tabbar's People

Contributors

andrewmarmion avatar andstelyc avatar glebkaf avatar ravensworth avatar slowyn avatar zjxiaohan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-native-underline-tabbar's Issues

OnChangeTab callback in child? Is there a componentHasBeenFocused?

I am able to use onChangeTab prop on the parent <ScrollableTabView> tag. But how do I execute some code inside the children that will fire when (and only when) the tab comes to focus?

Is there something like componentDidMount that will execute when tab is focused, in other words, a componentHasBeenFocused in the child? Or is there a workaround?

Custom views

Does this tab bar let us add new scenes on each click? For example, could i have flat lists with views, buttons, text , etc?

Current NPM release has incorrect entry point in package.json

As mentioned, in package.json on the current NPM release, there is this:

"main": "TabBar.js",

while the actual file in the package is tabBar.js, causing various Module Not Found errors when it's imported.

It looks like the current Github version has this fixed (tabBar.js was renamed to TabBar.js in a later commit), so please sync the npm package to your Github. Thanks!

Rendering initial tab other tab first tab

Thanks for contributing for react-native-underline-tabbar. I am making use of the library currently. could you please let me know how can I setup an initial tab other than first tab when my screen rendered?

I hope I won't be bothering you much. Kindly revert. Thank you in advance.

underline from 1st tab to current tab

Hi There,

I know its a feature request but is it possible to have underline start from the left bottom corner of the 1st tab till the right bottom corner of the current active tab.

I need a way to show the progress of a setup which comprises of multiple tabs.

Thanks & Regards.

using with react navigation and passing navigate props

navigate not working,appears null if it another tab selected.

class Chats extends React.Component {

   const { navigate } = this.props.navigation;
  renderItem={({item}) => <TouchableOpacity onPress={() => navigate('Chat')}><View style={{flex: 1,flexDirection:'row'}}>

> TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')
> 
> This error is located at:
>     in Chats (at App.js:294)
>     in StaticContainer (at SceneComponent.js:11)
>     in RCTView (at View.js:71)
>     in View (at SceneComponent.js:10)
>     in SceneComponent (created by ViewPagerAndroid)
>     in AndroidViewPager (at ViewPagerAndroid.android.js:238)
>     in ViewPagerAndroid (at createAnimatedComponent.js:147)
>     in AnimatedComponent (at index.js:246)
>     in RCTView (at View.js:71)
>     in View (at index.js:387)
>     in ScrollableTabView (at App.js:289)
>     in HomeScreen (at SceneView.js:31)
>     in SceneView (at CardStack.js:412)
>     in RCTView (at View.js:71)
>     in View (at CardStack.js:411)
>     in RCTView (at View.js:71)
>     in View (at CardStack.js:410)
>     in RCTView (at View.js:71)
>     in View (at createAnimatedComponent.js:147)
>     in AnimatedComponent (at Card.js:26)
>     in Card (at PointerEventsContainer.js:55)
>     in Container (at CardStack.js:454)
>     in RCTView (at View.js:71)
>     in View (at CardStack.js:383)
>     in RCTView (at View.js:71)
>     in View (at CardStack.js:382)
>     in CardStack (at CardStackTransitioner.js:97)
>     in RCTView (at View.js:71)
>     in View (at Transitioner.js:192)
>     in Transitioner (at CardStackTransitioner.js:49)
>     in CardStackTransitioner (at StackNavigator.js:60)
>     in Unknown (at createNavigator.js:52)
>     in Navigator (at createNavigationContainer.js:212)
>     in NavigationContainer (at App.js:323)
>     in App (at renderApplication.js:35)
>     in RCTView (at View.js:71)
>     in View (at AppContainer.js:102)
>     in RCTView (at View.js:71)
>     in View (at AppContainer.js:122)
>     in AppContainer (at renderApplication.js:34)
> render
>     index.delta?platform=android&dev=true&minify=false:58868:53
> proxiedMethod
>     index.delta?platform=android&dev=true&minify=false:34324:37
> finishClassComponent
>     index.delta?platform=android&dev=true&minify=false:7731:43
> updateClassComponent
>     index.delta?platform=android&dev=true&minify=false:7712:38
> beginWork
>     index.delta?platform=android&dev=true&minify=false:7987:42
> performUnitOfWork
>     index.delta?platform=android&dev=true&minify=false:9780:31
> workLoop
>     index.delta?platform=android&dev=true&minify=false:9832:49
> _invokeGuardedCallback
>     index.delta?platform=android&dev=true&minify=false:2774:21
> invokeGuardedCallback
>     index.delta?platform=android&dev=true&minify=false:2736:39
> renderRoot
>     index.delta?platform=android&dev=true&minify=false:9887:36
> performWorkOnRoot
>     index.delta?platform=android&dev=true&minify=false:10478:40
> performWork
>     index.delta?platform=android&dev=true&minify=false:10415:30
> batchedUpdates
>     index.delta?platform=android&dev=true&minify=false:10560:26
> batchedUpdates
>     index.delta?platform=android&dev=true&minify=false:4107:37
> _receiveRootNodeIDEvent
>     index.delta?platform=android&dev=true&minify=false:4190:23
> receiveTouches
>     index.delta?platform=android&dev=true&minify=false:4220:34
> __callFunction
>     index.delta?platform=android&dev=true&minify=false:2361:49
> <unknown>
>     index.delta?platform=android&dev=true&minify=false:2131:31
> __guardSafe
>     index.delta?platform=android&dev=true&minify=false:2323:13
> callFunctionReturnFlushedQueue
>     index.delta?platform=android&dev=true&minify=false:2130:21
> 

null is not an object (evaluating 'ref.setNativeProps')

null is not an object (evaluating 'ref.setNativeProps')

error from this block
applyTransformToUnderline
TabBar.js:139:8

applyTransformToUnderline(ref: any, scaleXFactor: number, dx: number) {
    const matrix = createTranslateXScaleX(scaleXFactor, dx);
    transformOrigin(matrix, { x: -0.5, y: 0, z: 0 });
    ref.setNativeProps({
      style: {
        transform: [
          {
            matrix,
          },
        ],
      },
    });
  }

I use "react-native": "0.46.4"

Not showing Advanced Tabs in Android

In IOS, its working fine
But in android, it gives error in this area :

`const containerStyle = {
paddingHorizontal: 20,
paddingVertical: 5,
borderRadius: 25,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: **styles.backgroundColor**,
opacity: **styles.opacity**,
transform: [{ scale: **styles.opacity** }],

};`

and says undefined is not an object (evaluating 'styles.textColor')
And when i put any random colors here, the error will disappear but shows nothing (no tabs).

error layout in the landscape mode

@Slowyn hi thanks for the tabber~ nice job~ Do you got chance to test the scrollable Tab on the landscape mode for ios or android (I mean switch from vertical mode to landscape mode) ? it is not positioned correctly.
I am using react-native-scrollable-tab-view: 0.8.0, and your latest version.
import TabBar from "react-native-underline-tabbar";

when I using the TabBar

<ScrollableTabView
              tabBarActiveTextColor="#53ac49"
              renderTabBar={() => <TabBar underlineColor="#53ac49" />}> <-- flow error in <TabBar/> tag
       <Page tabLabel={{label: "Page #1"}} label="Page #1"/>
                   ......          
</ScrollableTabView>

, the flow gives lots type error. I will try to post a screenShot of it when I got time.

outputRange must have at least 2 elements

Hi, I have a problem here.
Can you help me 🐛?

When ScrollableTabView had only one child(The number of children is dynamic),TabBar don't work.

<ScrollableTabView
       tabBarActiveTextColor={THEME_COLOR.main}
       renderTabBar={() => <TabBar underlineColor={THEME_COLOR.main} />}
>
      <View tabLabel={{label: "Page #1"}}/>
</ScrollableTabView>

Mysterious fontSize issue with tabBarTextStyle

This took me forever to hunt down what was even causing my problem, and frankly I'm stumped as to the underlying issue and how to solve it.

Code

<ScrollableTabView
  renderTabBar={() => (
    <TabBar
      underlineColor="black"
      activeTabTextStyle={{ color: 'black' }}
      tabBarTextStyle={{
        color: 'rgba(0,0,0,0.5)',
        fontSize: 16,      // <--- spoiler alert: this is causing my issue
        fontWeight: 'bold',
      }}
      tabBarStyle={{
        borderBottomColor: colors.lightGray,
      }}
    />
  )}
>
  <FlatList
    tabLabel={{ label: 'users' }}
    data={userData}
    renderItem={this.renderUserItem}
    refreshControl={
      <RefreshControl
        refreshing={this.state.usersRefreshing}
        onRefresh={this.refreshUsers}
      />
    }
  />
  <FlatList
    tabLabel={{ label: 'groups' }}
    data={groupData}
    renderItem={this.renderGroupItem}
    refreshControl={
      <RefreshControl
        refreshing={this.state.usersRefreshing}
        onRefresh={this.refreshUsers}
      />
    }
  />
</ScrollableTabView>

everything works well, EXCEPT with the FlatList when the list is shorter than the height of my screen (i.e. only two or three elements) I cannot scroll the FlatList AND I cannot pullToRefresh

The Fix

After trying everything, I found that if I removed the fontSize: 16 from the tabBarTextStyle on the TabBar all my scrolling worked as expected on the FlatList. Not ideal, but something I can deal with for now.

Any idea why this might be or how I can apply a fontSize without it disabling my scrolling on these FlatLists?

Underline spacing

Can we customize the distance between the underline and the text on the tab bar?

ScrollView Restore

demo
When the page slides,Tab don't follow to locate?I am Chinese,English is not good,Sorry,Thank you!

[iOS] Landscape mode can not scroll the tab

@Slowyn Thanks for the amazing lib, please take a look the issue i found,

  1. [ios] When rotate the app into landscape, the scrollableTab can not be scrolled anymore.
    Please refer to the gif for more info.

  2. [android and ios] Is that possible to add a auto-focus feature when rotate screen? for example, in android if i have 10 tabs, in landscape mode we click tab number 10, and when switch to vertical mode we can auto scroll to the position of tab number 10 rather than manually scroll to the most right to find it.

react-native: 0.55.3
react-native-scrollable-tab-view:0.8.0 (latest)
react-native-underline-tabbar: latest
iOS simulator-iPhone 8

landscapecannotdrag

react-native/Libraries/Utilities/MatrixMath

import React, { Component } from 'react';
7 | import { Text, TouchableOpacity, View, Animated, ScrollView } from 'react-native';

8 | import MatrixMath from 'react-native/Libraries/Utilities/MatrixMath';
| ^
9 |
10 | import styles from './Styles';

How Do You Evenly Space a Known Number of Tabs?

Say I have a set number of tabs and I know the labels won't overflow the width of the screen.

I'm struggling with how to evenly space the labels across the header like the below example:

snip20180810_16

Basically I want to use 'space-around' as if they were flex items but I can't seem to get it to work properly.

Any help would be greatly appreciated, thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.