Skip to content

Commit a711e19

Browse files
committed
Add fade gradient to TabController.TabBar edges when scroll overflows
1 parent 2e4b00a commit a711e19

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// TODO: use this component inside ScrollBar
2+
import React, {useRef, useEffect, useMemo} from 'react';
3+
import {Animated} from 'react-native';
4+
5+
import {Colors} from '../../style';
6+
import {Constants} from '../../helpers';
7+
import View from '../view';
8+
import Image from '../image';
9+
10+
const AnimatedImage = Animated.createAnimatedComponent(Image);
11+
12+
const ScrollBarGradient = ({
13+
visible,
14+
left,
15+
gradientWidth = 76,
16+
gradientHeight,
17+
gradientMargins = 0,
18+
height,
19+
gradientColor = Colors.white,
20+
gradientImage = require('./assets/gradientOverlay.png'),
21+
}) => {
22+
const gradientOpacity = useRef(new Animated.Value(0)).current;
23+
24+
useEffect(() => {
25+
Animated.timing(gradientOpacity, {
26+
toValue: Number(!!visible),
27+
duration: 100,
28+
useNativeDriver: true
29+
}).start();
30+
}, [visible]);
31+
32+
const imageTransform = useMemo(() => {
33+
return Constants.isRTL ? (left ? undefined : [{scaleX: -1}]) : left ? [{scaleX: -1}] : undefined;
34+
}, [left]);
35+
36+
const heightToUse = gradientHeight || height || '100%';
37+
return (
38+
<View
39+
animated
40+
pointerEvents="none"
41+
style={{
42+
opacity: gradientOpacity,
43+
width: gradientWidth,
44+
height: heightToUse,
45+
position: 'absolute',
46+
right: !left ? gradientMargins : undefined,
47+
left: left ? gradientMargins : undefined
48+
}}
49+
>
50+
<AnimatedImage
51+
source={gradientImage}
52+
style={{
53+
width: gradientWidth,
54+
height: heightToUse,
55+
tintColor: gradientColor,
56+
transform: imageTransform
57+
}}
58+
resizeMode={'stretch'}
59+
/>
60+
</View>
61+
);
62+
};
63+
64+
export default ScrollBarGradient;

src/components/tabController/TabBar.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import TabBarItem from './TabBarItem';
1111
// import ReanimatedObject from './ReanimatedObject';
1212
import {asBaseComponent, forwardRef} from '../../commons';
1313
import View from '../../components/view';
14+
import ScrollBarGradient from '../scrollBar/ScrollBarGradient';
1415
import {Colors, Spacings, Typography} from '../../style';
1516
import {Constants} from '../../helpers';
1617
import {LogService} from '../../services';
@@ -270,11 +271,32 @@ class TabBar extends PureComponent {
270271
};
271272

272273
onScroll = ({nativeEvent: {contentOffset}}) => {
274+
const {fadeLeft, fadeRight} = this.state;
273275
this.tabBarScrollOffset = contentOffset.x;
276+
const stateUpdate = {};
277+
// TODO: extract this logic to scrollbar presenter or something
278+
const leftThreshold = 50;
279+
if (this.tabBarScrollOffset > leftThreshold && !fadeLeft) {
280+
stateUpdate.fadeLeft = true;
281+
} else if (this.tabBarScrollOffset <= leftThreshold && fadeLeft) {
282+
stateUpdate.fadeLeft = false;
283+
}
284+
285+
const rightThreshold = (this.contentWidth - this.containerWidth);
286+
if (this.tabBarScrollOffset < rightThreshold && !fadeRight) {
287+
stateUpdate.fadeRight = true;
288+
} else if (this.tabBarScrollOffset >= rightThreshold && fadeRight) {
289+
stateUpdate.fadeRight = false;
290+
}
291+
292+
if (!_.isEmpty(stateUpdate)) {
293+
this.setState(stateUpdate);
294+
}
274295
};
275296

276297
onContentSizeChange = (width) => {
277-
if (width > this.containerWidth) {
298+
if (width > this.containerWidth && !this.contentWidth) {
299+
this.contentWidth = width;
278300
this.setState({scrollEnabled: true});
279301
}
280302
};
@@ -375,7 +397,7 @@ class TabBar extends PureComponent {
375397

376398
render() {
377399
const {height, enableShadow, containerStyle, testID} = this.props;
378-
const {itemsWidths, scrollEnabled} = this.state;
400+
const {itemsWidths, scrollEnabled, fadeLeft, fadeRight} = this.state;
379401
return (
380402
<View
381403
style={[styles.container, enableShadow && styles.containerShadow, {width: this.containerWidth}, containerStyle]}
@@ -400,6 +422,8 @@ class TabBar extends PureComponent {
400422
{this.renderSelectedIndicator()}
401423
</ScrollView>
402424
{_.size(itemsWidths) > 1 && <Code>{this.renderCodeBlock}</Code>}
425+
<ScrollBarGradient left visible={fadeLeft}/>
426+
<ScrollBarGradient visible={fadeRight}/>
403427
</View>
404428
);
405429
}

0 commit comments

Comments
 (0)