Skip to content

Commit b73cfdd

Browse files
committed
v1.0.7
1 parent 714e05d commit b73cfdd

File tree

6 files changed

+178
-7
lines changed

6 files changed

+178
-7
lines changed

Example/AnimatedSegmentControl/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class App extends Component {
1212
<View style={styles.container}>
1313
<SegmentControl
1414
values={['Segment1', 'Segment2', 'Segment3']}
15-
selectedIndex={1}
15+
selectedIndex={0}
1616
onChange={this.onSegmentValueChange}
1717
/>
1818
</View>

Example/AnimatedSegmentControl/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"dependencies": {
1010
"react": "16.8.3",
1111
"react-native": "0.59.10",
12-
"react-native-animated-segment-control": "^1.0.6"
12+
"react-native-animated-segment-control": "^1.0.7"
1313
},
1414
"devDependencies": {
1515
"@babel/core": "^7.5.4",

Example/AnimatedSegmentControl/yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4869,10 +4869,10 @@ react-is@^16.8.1, react-is@^16.8.3, react-is@^16.8.4:
48694869
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
48704870
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
48714871

4872-
react-native-animated-segment-control@^1.0.5:
4873-
version "1.0.5"
4874-
resolved "https://registry.yarnpkg.com/react-native-animated-segment-control/-/react-native-animated-segment-control-1.0.5.tgz#01b61b4083edbb47d75e73cc8934f2b9491bd29b"
4875-
integrity sha512-rdp5yA5o3ShbukGziUJUxP//LaQrs+b15QZQU2ofVP+oXXtE/D93lVWukrQ7s2V76yDaZ3VxbEZOksD1AsLwiQ==
4872+
react-native-animated-segment-control@^1.0.7:
4873+
version "1.0.7"
4874+
resolved "https://registry.yarnpkg.com/react-native-animated-segment-control/-/react-native-animated-segment-control-1.0.7.tgz#292b4cae145dcdee13a30fad74c49222c319f3a2"
4875+
integrity sha512-c53ozImblbYJrZKR/TF1izg8j5DQUn6geVkxTS/lfBgjdUu4AQWzqwmaJa0E8063EytHuCY6AsHl0QYpIjLJ7g==
48764876
dependencies:
48774877
metro-react-native-babel-preset "^0.55.0"
48784878

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-animated-segment-control",
3-
"version": "1.0.6",
3+
"version": "1.0.7",
44
"description": "A custom `SegmentControl` component, pretty much similar to native's SegmentControl but with animation",
55
"main": "index.js",
66
"scripts": {
File renamed without changes.

src/SegmentControl/index.ios.js

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
import { View, Animated, ViewPropTypes, Easing } from 'react-native'
4+
5+
import styles from './styles'
6+
import Segment from './Segment'
7+
8+
/**
9+
* A custom `SegmentControl` component, pretty much similar to native's SegmentControl but with animation.
10+
* Animates when changing the segment value.
11+
*/
12+
class SegmentControl extends React.Component {
13+
constructor(props) {
14+
super(props)
15+
16+
this.state = {
17+
selectedIndex: props.selectedIndex,
18+
segmentDimension: { width: 0, height: 0 },
19+
activeSegmentPosition: { x: props.offsetHeight, y: props.offsetHeight },
20+
positionAnimationValue: new Animated.Value(0)
21+
}
22+
}
23+
24+
/**
25+
* On segment change event.
26+
*
27+
* @param {Number} index
28+
*/
29+
onSegmentSelection = index => {
30+
const animate = () => {
31+
Animated.timing(this.state.positionAnimationValue, {
32+
toValue: this.state.activeSegmentPosition.x,
33+
duration: 150,
34+
easing: Easing.ease
35+
}).start(() => this.props.onChange(index))
36+
}
37+
38+
this.setState(
39+
prevState => ({
40+
selectedIndex: index,
41+
activeSegmentPosition: { x: prevState.segmentDimension.width * index + this.props.offsetHeight, y: prevState.activeSegmentPosition.y }
42+
}),
43+
animate
44+
)
45+
}
46+
47+
/**
48+
* Invoked on mount and layout change of `segmentContainer` view.
49+
*
50+
* @param {Object} event
51+
*/
52+
segmentOnLayout = event => {
53+
const { width, height } = event.nativeEvent.layout
54+
const segmentWidth = (width - this.props.offsetHeight * 2) / this.props.values.length
55+
56+
const animate = () => {
57+
Animated.timing(this.state.positionAnimationValue, {
58+
toValue: segmentWidth * this.state.selectedIndex + this.props.offsetHeight,
59+
duration: 100
60+
}).start()
61+
}
62+
63+
this.setState(() => ({
64+
segmentDimension: { width: segmentWidth, height }
65+
}), animate)
66+
}
67+
68+
render() {
69+
const { style, disable, activeSegmentStyle, segmentControlStyle, selectedTextStyle, unSelectedTextStyle } = this.props
70+
const { width, height } = this.state.segmentDimension
71+
const segmentHeight = height - this.props.offsetHeight * 2
72+
73+
const isDisabled = disable ? 'none' : 'auto'
74+
const extraStyles = disable ? styles.vivid : {}
75+
76+
return (
77+
<View style={[styles.mainContainer, style]} pointerEvents={isDisabled}>
78+
<View
79+
style={[styles.segmentContainer, extraStyles, { height, borderRadius: height }, segmentControlStyle]}
80+
onLayout={this.segmentOnLayout}
81+
>
82+
{this.props.values.map((segment, index) => (
83+
<Segment
84+
style={{ height: segmentHeight }}
85+
title={segment}
86+
textStyle={index !== this.state.selectedIndex ? unSelectedTextStyle : {...styles.activeText, ...selectedTextStyle}}
87+
onPress={() => this.onSegmentSelection(index)}
88+
/>
89+
))}
90+
<Animated.View
91+
style={[
92+
{
93+
width,
94+
height: segmentHeight,
95+
left: this.state.positionAnimationValue,
96+
top: this.state.activeSegmentPosition.y
97+
},
98+
styles.segment,
99+
styles.activeSegment,
100+
activeSegmentStyle,
101+
]}
102+
/>
103+
</View>
104+
</View>
105+
)
106+
}
107+
}
108+
109+
SegmentControl.defaultProps = {
110+
offsetHeight: 3,
111+
selectedIndex: 0,
112+
style: {},
113+
segmentControlStyle: {},
114+
activeSegmentStyle: {},
115+
selectedTextStyle: {},
116+
unSelectedTextStyle: {}
117+
}
118+
119+
SegmentControl.propTypes = {
120+
/**
121+
* Segment values that are rendered on the view itself.
122+
*/
123+
values: PropTypes.arrayOf(PropTypes.string).isRequired,
124+
125+
/**
126+
* To enable diable the segment control. Default value is `false`.
127+
*/
128+
disable: PropTypes.bool.isRequired,
129+
130+
/**
131+
* A callback function of segment index on change. Changed index is send on the callback as a param.
132+
*/
133+
onChange: PropTypes.func.isRequired,
134+
135+
/**
136+
* Index of the selected segment
137+
*/
138+
selectedIndex: PropTypes.number,
139+
140+
/**
141+
* Active Segment's offset height. Basically a padding.
142+
*/
143+
offsetHeight: PropTypes.number,
144+
145+
/**
146+
* Styles props of main wrapper
147+
*/
148+
style: ViewPropTypes.style,
149+
150+
/**
151+
* Styles props of segment control
152+
*/
153+
segmentControlStyle: ViewPropTypes.style,
154+
155+
/**
156+
* Styles props of active segment
157+
*/
158+
activeSegmentStyle: ViewPropTypes.style,
159+
160+
/**
161+
* Selected Segment text style.
162+
*/
163+
selectedTextStyle: ViewPropTypes.style,
164+
165+
/**
166+
* Unselected Segment text style.
167+
*/
168+
unSelectedTextStyle: ViewPropTypes.style,
169+
}
170+
171+
export default SegmentControl

0 commit comments

Comments
 (0)