@@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
66import _ from 'lodash' ;
77import Reanimated , { Easing } from 'react-native-reanimated' ;
88import { State } from 'react-native-gesture-handler' ;
9- import { timing , fract } from 'react-native-redash' ;
9+ import { timing , fract , between } from 'react-native-redash' ;
1010import { Constants } from '../../helpers' ;
1111import TabBarContext from './TabBarContext' ;
1212import TabBar from './TabBar' ;
@@ -16,12 +16,16 @@ import PageCarousel from './PageCarousel';
1616
1717const {
1818 and,
19+ abs,
1920 cond,
2021 call,
2122 Code,
2223 Clock,
2324 clockRunning,
25+ diff,
2426 eq,
27+ floor,
28+ lessThan,
2529 neq,
2630 not,
2731 set,
@@ -52,10 +56,6 @@ class TabController extends Component {
5256 * callback for when index has change (will not be called on ignored items)
5357 */
5458 onChangeIndex : PropTypes . func ,
55- // /**
56- // * callback for when tab selected
57- // */
58- // onTabSelected: PropTypes.func,
5959 /**
6060 * When using TabController.PageCarousel this should be turned on
6161 */
@@ -67,36 +67,22 @@ class TabController extends Component {
6767 activeOpacity : 0.2
6868 } ;
6969
70- state = {
71- selectedIndex : this . props . selectedIndex ,
72- itemStates : [ ]
73- } ;
74-
75- _targetPage = new Value ( this . props . selectedIndex ) ;
76- _currentPage = new Value ( this . props . selectedIndex ) ;
77- _carouselOffset = new Value ( this . props . selectedIndex * Math . round ( Constants . screenWidth ) ) ;
78-
79- shouldComponentUpdate ( nextProps ) {
80- if ( nextProps . selectedIndex !== this . props . selectedIndex ) {
81- return false ;
82- }
83- return true ;
84- }
85-
86- getProviderContextValue = ( ) => {
87- const { itemStates, selectedIndex} = this . state ;
88- const { onChangeIndex, asCarousel} = this . props ;
89- return {
90- selectedIndex,
91- currentPage : this . _currentPage ,
92- targetPage : this . _targetPage ,
93- carouselOffset : this . _carouselOffset ,
94- itemStates,
70+ constructor ( props ) {
71+ super ( props ) ;
72+
73+ this . state = {
74+ selectedIndex : this . props . selectedIndex ,
75+ asCarousel : this . props . asCarousel ,
76+ itemStates : [ ] ,
77+ // animated values
78+ targetPage : new Value ( this . props . selectedIndex ) ,
79+ currentPage : new Value ( this . props . selectedIndex ) ,
80+ carouselOffset : new Value ( this . props . selectedIndex * Math . round ( Constants . screenWidth ) ) ,
81+ // // callbacks
9582 registerTabItems : this . registerTabItems ,
96- onChangeIndex,
97- asCarousel
83+ onChangeIndex : this . props . onChangeIndex
9884 } ;
99- } ;
85+ }
10086
10187 registerTabItems = ( tabItemsCount , ignoredItems ) => {
10288 const itemStates = _ . times ( tabItemsCount , ( ) => new Value ( State . UNDETERMINED ) ) ;
@@ -108,11 +94,13 @@ class TabController extends Component {
10894 } ;
10995
11096 renderCodeBlock = ( ) => {
111- const { itemStates, ignoredItems} = this . state ;
97+ const { itemStates, ignoredItems, currentPage , targetPage , carouselOffset } = this . state ;
11298 const { selectedIndex} = this . props ;
11399 const clock = new Clock ( ) ;
114100 const fromPage = new Value ( selectedIndex ) ;
115101 const toPage = new Value ( selectedIndex ) ;
102+ const isAnimating = new Value ( 0 ) ;
103+ const isScrolling = new Value ( 0 ) ;
116104
117105 return block ( [
118106 /* Page change by TabBar */
@@ -123,38 +111,48 @@ class TabController extends Component {
123111 cond ( and ( eq ( state , State . END ) , ! ignoredItem ) , [
124112 set ( fromPage , toPage ) ,
125113 set ( toPage , index ) ,
126- set ( this . _targetPage , index )
114+ set ( targetPage , index )
127115 ] ) )
128116 ] ;
129117 } ) ,
130118
131- cond ( neq ( this . _currentPage , toPage ) ,
132- set ( this . _currentPage ,
133- timing ( { clock, from : fromPage , to : toPage , duration : 300 , easing : Easing . bezier ( 0.34 , 1.56 , 0.64 , 1 ) } ) ) ) ,
134-
135- /* Page change by Carousel */
136- onChange ( this . _carouselOffset , [
137- cond ( not ( clockRunning ( clock ) ) , [
138- set ( this . _currentPage ,
139- interpolate ( round ( this . _carouselOffset ) , {
119+ // Animate currentPage to its target
120+ cond ( neq ( currentPage , toPage ) , [
121+ set ( isAnimating , 1 ) ,
122+ set ( currentPage ,
123+ timing ( { clock, from : fromPage , to : toPage , duration : 300 , easing : Easing . bezier ( 0.34 , 1.56 , 0.64 , 1 ) } ) )
124+ ] ) ,
125+ // Set isAnimating flag off
126+ cond ( and ( eq ( isAnimating , 1 ) , not ( clockRunning ( clock ) ) ) , set ( isAnimating , 0 ) ) ,
127+
128+ /* Page change by Carousel scroll */
129+ onChange ( carouselOffset , [
130+ set ( isScrolling , lessThan ( round ( abs ( diff ( carouselOffset ) ) ) , round ( Constants . screenWidth ) ) ) ,
131+ cond ( and ( not ( isAnimating ) ) , [
132+ set ( currentPage ,
133+ interpolate ( round ( carouselOffset ) , {
140134 inputRange : itemStates . map ( ( v , i ) => Math . round ( i * Constants . screenWidth ) ) ,
141135 outputRange : itemStates . map ( ( v , i ) => i )
142136 } ) ) ,
143- set ( toPage , this . _currentPage ) ,
144- cond ( eq ( fract ( this . _currentPage ) , 0 ) , set ( this . _targetPage , this . _currentPage ) )
137+ set ( toPage , currentPage )
145138 ] )
146139 ] ) ,
140+ // Update/Sync target page when scrolling is done
141+ cond ( and ( eq ( isScrolling , 1 ) , eq ( floor ( abs ( diff ( carouselOffset ) ) ) , 0 ) ) , [
142+ set ( isScrolling , 0 ) ,
143+ cond ( not ( between ( fract ( currentPage ) , 0.1 , 0.9 , 1 ) ) , set ( targetPage , round ( currentPage ) ) )
144+ ] ) ,
147145
148146 /* Invoke index change */
149- onChange ( toPage , call ( [ toPage ] , this . onPageChange ) )
147+ onChange ( targetPage , call ( [ targetPage ] , this . onPageChange ) )
150148 ] ) ;
151149 } ;
152150
153151 render ( ) {
154152 const { itemStates} = this . state ;
155153
156154 return (
157- < TabBarContext . Provider value = { this . getProviderContextValue ( ) } >
155+ < TabBarContext . Provider value = { this . state } >
158156 { this . props . children }
159157 { ! _ . isEmpty ( itemStates ) && < Code > { this . renderCodeBlock } </ Code > }
160158 </ TabBarContext . Provider >
0 commit comments