@@ -11,13 +11,26 @@ import TabBarItem from './TabBarItem';
11
11
// import ReanimatedObject from './ReanimatedObject';
12
12
import { asBaseComponent , forwardRef } from '../../commons' ;
13
13
import View from '../../components/view' ;
14
- import { Colors , Spacings } from '../../style' ;
14
+ import { Colors , Spacings , Typography } from '../../style' ;
15
15
import { Constants } from '../../helpers' ;
16
16
import { LogService } from '../../services' ;
17
17
18
+ const { Code, Value, interpolate, block, set} = Reanimated ;
19
+
18
20
const DEFAULT_HEIGHT = 48 ;
19
21
const INDICATOR_INSET = Spacings . s4 ;
20
- const { Code, Value, interpolate, block, set} = Reanimated ;
22
+
23
+ const DEFAULT_LABEL_STYLE = {
24
+ ...Typography . text80 ,
25
+ fontWeight : '400' ,
26
+ letterSpacing : 0
27
+ } ;
28
+
29
+ const DEFAULT_SELECTED_LABEL_STYLE = {
30
+ ...Typography . text80 ,
31
+ fontWeight : '700' ,
32
+ letterSpacing : 0
33
+ } ;
21
34
22
35
/**
23
36
* @description : TabController's TabBar component
@@ -88,10 +101,17 @@ class TabBar extends PureComponent {
88
101
/**
89
102
* Pass to center selected item
90
103
*/
91
- centerSelected : PropTypes . bool
104
+ centerSelected : PropTypes . bool ,
105
+ /**
106
+ * (Experimental) Pass to optimize loading time by measuring tab bar items text
107
+ * instead of waiting for onLayout
108
+ */
109
+ optimize : PropTypes . bool
92
110
} ;
93
111
94
112
static defaultProps = {
113
+ labelStyle : DEFAULT_LABEL_STYLE ,
114
+ selectedLabelStyle : DEFAULT_SELECTED_LABEL_STYLE
95
115
// containerWidth: Constants.screenWidth
96
116
} ;
97
117
@@ -123,6 +143,9 @@ class TabBar extends PureComponent {
123
143
} ;
124
144
125
145
this . registerTabItems ( ) ;
146
+ if ( props . items && props . optimize ) {
147
+ this . measureItems ( ) ;
148
+ }
126
149
}
127
150
128
151
get containerWidth ( ) {
@@ -144,7 +167,29 @@ class TabBar extends PureComponent {
144
167
145
168
get centerOffset ( ) {
146
169
const { centerSelected} = this . props ;
147
- return centerSelected ? Constants . screenWidth / 2 : 0 ;
170
+ const guesstimateCenterValue = 60 ;
171
+ return centerSelected ? Constants . screenWidth / 2 - guesstimateCenterValue : 0 ;
172
+ }
173
+
174
+ measureItems = async ( ) => {
175
+ const { labelStyle} = this . props ;
176
+ const measuring = _ . map ( this . props . items , ( item ) => {
177
+ return Typography . measureTextSize ( item . label , labelStyle ) ;
178
+ } ) ;
179
+ const results = await Promise . all ( measuring ) ;
180
+ const widths = _ . map ( results , item => item . width + Spacings . s4 * 2 ) ;
181
+ const offsets = [ ] ;
182
+ _ . forEach ( widths , ( width , index ) => {
183
+ if ( index === 0 ) {
184
+ offsets [ index ] = this . centerOffset ;
185
+ } else {
186
+ offsets [ index ] = widths [ index - 1 ] + offsets [ index - 1 ] ;
187
+ }
188
+ } ) ;
189
+ this . _itemsWidths = widths ;
190
+ this . _itemsOffsets = offsets ;
191
+ // TODO: consider saving this setState and ride registerTabItems setState
192
+ this . setItemsLayouts ( ) ;
148
193
}
149
194
150
195
registerTabItems ( ) {
@@ -174,40 +219,42 @@ class TabBar extends PureComponent {
174
219
}
175
220
176
221
// TODO: move this logic into a ScrollPresenter or something
177
- focusSelected = ( [ index ] ) => {
222
+ focusSelected = ( [ index ] , animated = true ) => {
178
223
const { centerSelected} = this . props ;
179
224
const itemOffset = this . _itemsOffsets [ index ] ;
180
225
const itemWidth = this . _itemsWidths [ index ] ;
226
+ const screenCenter = Constants . screenWidth / 2 ;
181
227
182
228
if ( itemOffset && itemWidth ) {
183
229
if ( centerSelected ) {
184
- this . tabBar . current . scrollTo ( { x : itemOffset - this . centerOffset + itemWidth / 2 } ) ;
230
+ this . tabBar . current . scrollTo ( { x : itemOffset - screenCenter + itemWidth / 2 , animated } ) ;
185
231
} else if ( itemOffset < this . tabBarScrollOffset ) {
186
- this . tabBar . current . scrollTo ( { x : itemOffset - itemWidth } ) ;
232
+ this . tabBar . current . scrollTo ( { x : itemOffset - itemWidth , animated } ) ;
187
233
} else if ( itemOffset + itemWidth > this . tabBarScrollOffset + this . containerWidth ) {
188
234
const offsetChange = Math . max ( 0 , itemOffset - ( this . tabBarScrollOffset + this . containerWidth ) ) ;
189
- this . tabBar . current . scrollTo ( { x : this . tabBarScrollOffset + offsetChange + itemWidth } ) ;
235
+ this . tabBar . current . scrollTo ( { x : this . tabBarScrollOffset + offsetChange + itemWidth , animated } ) ;
190
236
}
191
237
}
192
238
} ;
193
239
240
+ // TODO: replace with measureItems logic
194
241
onItemLayout = ( { width, x} , itemIndex ) => {
195
242
this . _itemsWidths [ itemIndex ] = width ;
196
243
this . _itemsOffsets [ itemIndex ] = x ;
197
244
if ( ! _ . includes ( this . _itemsWidths , null ) ) {
198
- const { selectedIndex} = this . context ;
199
- const itemsOffsets = _ . map ( this . _itemsOffsets , offset => offset + INDICATOR_INSET ) ;
200
- const itemsWidths = _ . map ( this . _itemsWidths , ( width ) => width - INDICATOR_INSET * 2 ) ;
201
-
202
- this . setState ( { itemsWidths, itemsOffsets} ) ;
203
- const selectedItemOffset = itemsOffsets [ selectedIndex ] - INDICATOR_INSET ;
204
-
205
- if ( selectedItemOffset + this . _itemsWidths [ selectedIndex ] > Constants . screenWidth ) {
206
- this . tabBar . current . scrollTo ( { x : selectedItemOffset , animated : true } ) ;
207
- }
245
+ this . setItemsLayouts ( ) ;
208
246
}
209
247
} ;
210
248
249
+ setItemsLayouts = ( ) => {
250
+ const { selectedIndex} = this . context ;
251
+ const itemsOffsets = _ . map ( this . _itemsOffsets , offset => offset + INDICATOR_INSET ) ;
252
+ const itemsWidths = _ . map ( this . _itemsWidths , ( width ) => width - INDICATOR_INSET * 2 ) ;
253
+
254
+ this . setState ( { itemsWidths, itemsOffsets} ) ;
255
+ this . focusSelected ( [ selectedIndex ] , false ) ;
256
+ }
257
+
211
258
onScroll = ( { nativeEvent : { contentOffset} } ) => {
212
259
this . tabBarScrollOffset = contentOffset . x ;
213
260
} ;
@@ -229,6 +276,7 @@ class TabBar extends PureComponent {
229
276
renderTabBarItems ( ) {
230
277
const { itemStates} = this . context ;
231
278
const {
279
+ optimize,
232
280
items,
233
281
labelColor,
234
282
selectedLabelColor,
@@ -257,11 +305,12 @@ class TabBar extends PureComponent {
257
305
selectedIconColor = { selectedIconColor }
258
306
activeBackgroundColor = { activeBackgroundColor }
259
307
key = { item . label }
308
+ width = { this . _itemsWidths [ index ] }
260
309
{ ...item }
261
310
{ ...this . context }
262
311
index = { index }
263
312
state = { itemStates [ index ] }
264
- onLayout = { this . onItemLayout }
313
+ onLayout = { optimize ? undefined : this . onItemLayout }
265
314
/>
266
315
) ;
267
316
} ) ;
0 commit comments