├── .gitignore
├── README.md
├── examples.gif
├── index.js
├── package.json
└── src
├── styles.js
└── switch.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Image examples
7 | examples.gif
8 |
9 | # Runtime data
10 | pids
11 | *.pid
12 | *.seed
13 | *.pid.lock
14 |
15 | # Directory for instrumented libs generated by jscoverage/JSCover
16 | lib-cov
17 |
18 | # Coverage directory used by tools like istanbul
19 | coverage
20 |
21 | # nyc test coverage
22 | .nyc_output
23 |
24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
25 | .grunt
26 |
27 | # node-waf configuration
28 | .lock-wscript
29 |
30 | # Compiled binary addons (http://nodejs.org/api/addons.html)
31 | build/Release
32 |
33 | # Dependency directories
34 | node_modules
35 | jspm_packages
36 |
37 | # Optional npm cache directory
38 | .npm
39 |
40 | # Optional eslint cache
41 | .eslintcache
42 |
43 | # Optional REPL history
44 | .node_repl_history
45 |
46 | # Output of 'npm pack'
47 | *.tgz
48 |
49 | # Yarn Integrity file
50 | .yarn-integrity
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-customisable-switch
2 | A React Native module that allows you to customize switch (style, form and animation), available for android and IOS.
3 |
4 | ### Content
5 | - [Installation](#installation)
6 | - [Examples](#usage-example)
7 | - [Properties](#component-properties)
8 | - [Questions](#questions)
9 |
10 | ### Installation
11 | ```bash
12 | npm install --save react-native-customisable-switch
13 | ```
14 |
15 | ### Examples
16 |
17 |
18 |
19 |
20 | ```javascript
21 | import React, { Component } from 'react';
22 | import { Text, View } from 'react-native';
23 | import Switch from 'react-native-customisable-switch';
24 |
25 | export default class Test extends Component {
26 | constructor(props) {
27 | super(props);
28 | this.state = {
29 | switchOneValue: false,
30 | switchTwoValue: false,
31 | switchThreeValue: true,
32 | };
33 | }
34 |
35 | render() {
36 | const {
37 | switchOneValue,
38 | switchTwoValue,
39 | switchOneValue,
40 | } = this.state;
41 |
42 | return(
43 |
44 |
45 | this.setState({ switchOneValue: !switchOneValue })}
48 | />
49 |
50 |
51 | this.setState({ switchTwoValue: !switchTwoValue })}
54 | activeText={''}
55 | inactiveText={''}
56 | fontSize={16}
57 | activeTextColor={'rgba(255, 255, 255, 1)'}
58 | inactiveTextColor={'rgba(255, 255, 255, 1)'}
59 | activeBackgroundColor={'rgba(50, 163, 50, 1)'}
60 | inactiveBackgroundColor={'rgba(137, 137, 137, 1)'}
61 | activeButtonBackgroundColor={'rgba(255, 255, 255, 1)'}
62 | inactiveButtonBackgroundColor={'rgba(255, 255, 255, 1)'}
63 | switchWidth={70}
64 | switchHeight={30}
65 | switchBorderRadius={0}
66 | switchBorderColor={'rgba(0, 0, 0, 1)'}
67 | switchBorderWidth={0}
68 | buttonWidth={25}
69 | buttonHeight={25}
70 | buttonBorderRadius={0}
71 | buttonBorderColor={'rgba(0, 0, 0, 1)'}
72 | buttonBorderWidth={0}
73 | animationTime={150}
74 | padding={true}
75 | />
76 |
77 |
78 | this.setState({ switchThreeValue: !switchThreeValue })}
81 | activeText={'On'}
82 | inactiveText={'Off'}
83 | fontSize={16}
84 | switchWidth={70}
85 | switchHeight={25}
86 | switchBorderRadius={12}
87 | switchBorderWidth={0}
88 | buttonWidth={25}
89 | buttonHeight={40}
90 | buttonBorderRadius={20}
91 | buttonBorderColor={'rgba(0, 0, 0, 1)'}
92 | buttonBorderWidth={0}
93 | animationTime={150}
94 | padding={true}
95 | />
96 |
97 |
98 | )
99 | }
100 | }
101 |
102 | const styles = StyleSheet.create({
103 | container: {
104 | flex: 1,
105 | backgroundColor: '#464857',
106 | justifyContent: 'center',
107 | alignItems: 'center',
108 | },
109 | )};
110 | ```
111 |
112 | ### Component Properties
113 |
114 | | Property | Type | Default Value | Description |
115 | |-------------------------|----------|--------------------------|---------------------------------------------------------------------------|
116 | | value | boolean | false | Switch value to determine whether or not the switch is active or inactive |
117 | | onChangeValue | function | () => null | Function to handle the change of the value property |
118 | | activeText | string | "On" | Text when the switch is activate |
119 | | inactiveText | string | "Off" | Text when the switch is inactive |
120 | | fontSize | number | 16 | Text Size for `activeText` and `inactiveText` |
121 | | activeTextColor | string | "rgba(255, 255, 255, 1)" | Text color of `activeText` |
122 | | inactiveTextColor | string | "rgba(255, 255, 255, 1)" | Text color of `inactiveText` |
123 | | activeBackgroundColor | string | "rgba(50, 163, 50, 1)" | Background color of the switch while active |
124 | | inactiveBackgroundColor | string | "rgba(137, 137, 137, 1)" | Background color of the switch while inactive |
125 | | switchWidth | number | 70 | Width of the switch |
126 | | switchHeight | number | 30 | Height of the switch |
127 | | switchBorderRadius | number | 15 | Border radius of the switch |
128 | | switchBorderColor | string | "rgba(0, 0, 0, 1)" | Border color of the switch |
129 | | switchBorderWidth | number | 0 | Border width of the switch |
130 | | buttonWidth | number | 25 | Width of the button in the switch |
131 | | buttonHeight | number | 25 | Height of the button in the switch |
132 | | buttonBorderRadius | number | 15 | Border radius of the button in the switch |
133 | | buttonBorderColor | string | "rgba(0, 0, 0, 1)" | Border color of the button in the switch |
134 | | buttonBorderWidth | number | 0 | Border width of the button in the switch |
135 | | animationTime | number | 150 | Time of toggle animation in milliseconds |
136 | | padding | boolean | true | Whether the switch has a horizontal padding of 5 or not |
137 |
138 |
139 | ### Questions
140 | Create an issue (https://github.com/baderahmed/react-native-customisable-switch/issues)
141 |
--------------------------------------------------------------------------------
/examples.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baderahmed/react-native-customisable-switch/118fe5aa51150b8c471c081a23ba38087aa210c6/examples.gif
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import Switch from "./src/switch.js";
2 |
3 | export default Switch;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-customisable-switch",
3 | "version": "0.1.0",
4 | "description": "A React Native module that allows you to customize switch (style, form and animation), availble for android and IOS.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/baderahmed/react-native-customisable-switch.git#commit-ish"
12 | },
13 | "keywords": [
14 | "react-native",
15 | "switch",
16 | "android",
17 | "ios",
18 | "disign",
19 | "form",
20 | "color",
21 | "backgroundColor",
22 | "size"
23 | ],
24 | "author": "Bader Ahmed Tellili ",
25 | "license": "ISC",
26 | "bugs": {
27 | "url": "https://github.com/baderahmed/react-native-customisable-switch/issues"
28 | },
29 | "homepage": "https://github.com/baderahmed/react-native-customisable-switch/tree/commit-ish#readme"
30 | }
31 |
--------------------------------------------------------------------------------
/src/styles.js:
--------------------------------------------------------------------------------
1 |
2 | import { StyleSheet, Dimensions } from 'react-native';
3 |
4 | const deviceHeight = Dimensions.get('window').height;
5 | const deviceWidth = Dimensions.get('window').width;
6 |
7 | export default StyleSheet.create({
8 | container: {
9 | justifyContent: 'center',
10 | alignItems: 'center',
11 | backgroundColor: 'transparent',
12 | flexDirection: 'column',
13 | },
14 | animatedContainer: {
15 | flex: 1,
16 | flexDirection: 'row',
17 | justifyContent: 'center',
18 | alignItems: 'center',
19 | },
20 | textContainer: {
21 | flex: 1,
22 | flexDirection: 'row',
23 | justifyContent: 'center',
24 | alignItems: 'center',
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/src/switch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | Text,
4 | TouchableWithoutFeedback,
5 | View,
6 | Animated,
7 | } from 'react-native';
8 | import PropTypes from 'prop-types';
9 | import styles from './styles.js';
10 |
11 | export default class Switch extends Component {
12 | static propTypes = {
13 | value: PropTypes.bool,
14 | onChangeValue: PropTypes.func,
15 | activeText: PropTypes.string,
16 | inactiveText: PropTypes.string,
17 | fontSize: PropTypes.number,
18 | activeTextColor: PropTypes.string,
19 | inactiveTextColor: PropTypes.string,
20 | activeBackgroundColor: PropTypes.string,
21 | inactiveBackgroundColor: PropTypes.string,
22 | activeButtonBackgroundColor: PropTypes.string,
23 | inactiveButtonBackgroundColor: PropTypes.string,
24 | switchWidth: PropTypes.number,
25 | switchHeight: PropTypes.number,
26 | switchBorderRadius: PropTypes.number,
27 | switchBorderColor: PropTypes.string,
28 | switchBorderWidth: PropTypes.number,
29 | buttonWidth: PropTypes.number,
30 | buttonHeight: PropTypes.number,
31 | buttonBorderRadius: PropTypes.number,
32 | buttonBorderColor: PropTypes.string,
33 | buttonBorderWidth: PropTypes.number,
34 | animationTime: PropTypes.number,
35 | padding: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
36 | shadowColor: PropTypes.string,
37 | shadowOffset: PropTypes.object,
38 | shadowRadius: PropTypes.number,
39 | shadowOpacity: PropTypes.number,
40 | };
41 |
42 | static defaultProps = {
43 | value: false,
44 | onChangeValue: () => null,
45 | activeText: '',
46 | inactiveText: '',
47 | fontSize: 16,
48 | activeTextColor: 'rgba(255, 255, 255, 1)',
49 | inactiveTextColor: 'rgba(255, 255, 255, 1)',
50 | activeBackgroundColor: 'rgba(50, 163, 50, 1)',
51 | inactiveBackgroundColor: 'rgba(137, 137, 137, 1)',
52 | activeButtonBackgroundColor: 'rgba(255, 255, 255, 1)',
53 | inactiveButtonBackgroundColor: 'rgba(255, 255, 255, 1)',
54 | switchWidth: 70,
55 | switchHeight: 30,
56 | switchBorderRadius: 15,
57 | switchBorderColor: 'rgba(0, 0, 0, 1)',
58 | switchBorderWidth: 0,
59 | buttonWidth: 25,
60 | buttonHeight: 25,
61 | buttonBorderRadius: 15,
62 | buttonBorderColor: 'rgba(0, 0, 0, 1)',
63 | buttonBorderWidth: 0,
64 | animationTime: 150,
65 | padding: 5,
66 | shadowColor: '#000',
67 | shadowOffset: {width: 0, height: 0},
68 | shadowRadius: 0,
69 | shadowOpacity: 1,
70 | }
71 |
72 | constructor(props, context) {
73 | super(props, context);
74 | // Backwards compatibility: `padding` used to be bool, where `true = 5`
75 | this.padding = props.padding === true ? 5 : (props.padding || 0);
76 | this.transformValue = (props.switchWidth - props.buttonWidth - this.padding);
77 | this.state = {
78 | transformValue: new Animated.Value(props.value ? this.transformValue : this.padding),
79 | backgroundColor: new Animated.Value(props.value ? 90 : -90),
80 | buttonBackgroundColor: new Animated.Value(props.value ? 90 : -90),
81 | };
82 | }
83 |
84 | componentDidUpdate(prevProps) {
85 | const { value } = this.props;
86 | if (value !== prevProps) this.startGroupAnimations();
87 | }
88 |
89 | startGroupAnimations = () => {
90 | const { animationTime, onChangeValue, value } = this.props;
91 | Animated.parallel([
92 | Animated.spring(this.state.transformValue, {
93 | toValue: value ? this.transformValue : this.padding,
94 | duration: animationTime,
95 | }),
96 | Animated.timing(this.state.backgroundColor, {
97 | toValue: value ? 75 : -75,
98 | duration: animationTime,
99 | }),
100 | Animated.timing(this.state.buttonBackgroundColor, {
101 | toValue: value ? 75 : -75,
102 | duration: animationTime,
103 | })
104 | ]).start();
105 | }
106 |
107 | render() {
108 | const {
109 | transformValue,
110 | backgroundColor,
111 | buttonBackgroundColor,
112 | } = this.state;
113 |
114 | const {
115 | value,
116 | onChangeValue,
117 | activeText,
118 | inactiveText,
119 | fontSize,
120 | activeTextColor,
121 | inactiveTextColor,
122 | activeBackgroundColor,
123 | inactiveBackgroundColor,
124 | activeButtonBackgroundColor,
125 | inactiveButtonBackgroundColor,
126 | switchWidth,
127 | switchHeight,
128 | switchBorderRadius,
129 | switchBorderColor,
130 | switchBorderWidth,
131 | buttonWidth,
132 | buttonHeight,
133 | buttonBorderRadius,
134 | buttonBorderColor,
135 | buttonBorderWidth,
136 | shadowColor,
137 | shadowOffset,
138 | shadowRadius,
139 | shadowOpacity,
140 | } = this.props;
141 |
142 | const backgroundColorValue = backgroundColor.interpolate({
143 | inputRange: [-90, 90],
144 | outputRange: [
145 | inactiveBackgroundColor,
146 | activeBackgroundColor,
147 | ],
148 | });
149 |
150 | const buttonBackgroundColorValue = buttonBackgroundColor.interpolate({
151 | inputRange: [-90, 90],
152 | outputRange: [
153 | inactiveButtonBackgroundColor,
154 | activeButtonBackgroundColor,
155 | ],
156 | });
157 |
158 | const containerHeight = switchHeight > buttonHeight ? switchHeight : buttonHeight;
159 | const containerWidth = switchWidth > buttonWidth ? switchWidth : buttonWidth;
160 |
161 | return (
162 |
165 |
174 |
188 |
189 |
190 |
191 | {value ? activeText : ''}
192 |
193 |
194 |
195 |
196 | {value ? '' : inactiveText}
197 |
198 |
199 |
200 |
201 |
219 |
220 |
221 | );
222 | }
223 | }
224 |
--------------------------------------------------------------------------------