Skip to content

Commit facddb0

Browse files
committed
init commit
0 parents  commit facddb0

File tree

8 files changed

+378
-0
lines changed

8 files changed

+378
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2017 Christoph Michel
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# react-native-dynamically-selected-picker
2+
3+
React Native Picker for Android and IOS with dynamically updating selected items on scroll.
4+
5+
![](src/README/android.gif)
6+
![](src/README/ios.gif)
7+
8+
## installation
9+
10+
`yarn add react-native-dynamically-selected-picker`
11+
12+
or
13+
14+
`npm i react-native-dynamically-selected-picker`
15+
16+
#Basic usage
17+
18+
```
19+
import DynamicallySelectedPicker from 'react-native-dynamically-selected-picker';
20+
21+
<DynamicallySelectedPicker
22+
items={[
23+
{
24+
value: 1,
25+
label: 'Item 1',
26+
},
27+
{
28+
value: 2,
29+
label: 'Item 2',
30+
},
31+
{
32+
value: 3,
33+
label: 'Item 3',
34+
},
35+
]}
36+
onScrollDynamicallyChange={({index, item}) => {
37+
this.setState({selectedItemIndex: index});
38+
}}
39+
height={300}
40+
width={300}
41+
/>
42+
```
43+
44+
## Properties
45+
46+
| Prop | Default | Type | Description |
47+
| :------------- | :-------------: | :------: | :---------------------------------------------------------------------------------------------------------- |
48+
| items | [{value: 0, label: 'No items'}] | `Array<object>` | - |
49+
| onScrollDynamicallyChange | - | `func` | Returns selected item object and selected index |
50+
| onScrollBegin | - | `func` | Returns selected item object and selected index |
51+
| onScrollEnd | - | `func` | Returns selected item object and selected index |
52+
| initialSelectedIndex | 0 | `number` | Set index number of initial item. |
53+
| transparentItemRows | 3 | `number` | Set number of items at top and bottom of selected index. |
54+
| width | 200 | `number` | - |
55+
| height | 200 | `number` | - |
56+
| itemsColor | #000 | `string` | - |
57+
| selectedItemBorderColor | '#cecece' | `string` | - |
58+
| fontSize | - | `number` | - |
59+
| fontFamily | 'Arial | `string` | - |
60+
| topGradientColors | [...] | `Array<string>` | See default value in source.
61+
| bottomGradientColors | [...] | `Array<string>` | See default value in source. |

package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "react-native-dynamically-selected-picker",
3+
"version": "1.0.0",
4+
"description": "React Native Custom Picker for Android and IOS with onScroll change selected items",
5+
"keywords": [
6+
"ReactNative",
7+
"OnSwipePicker",
8+
"DynamicSelect",
9+
"Selector",
10+
"SelectPicker",
11+
"OnSwipePicker",
12+
"IosStyleAndroidPicker",
13+
"IosAndroidPicker",
14+
"OnScrollPicker",
15+
"picker",
16+
"swiper",
17+
"OnScrollChangePicker"
18+
],
19+
"main": "src/index.js",
20+
"scripts": {
21+
"test": "echo \"Error: no test specified\" && exit 1"
22+
},
23+
"repository": {
24+
"type": "git",
25+
"url": "git+https://github.com/sosog/react-native-dynamically-selected-picker.git"
26+
},
27+
"bugs": {
28+
"url": "https://github.com/sosog/react-native-dynamically-selected-picker/issues"
29+
},
30+
"homepage": "https://github.com/sosog/react-native-dynamically-selected-picker#readme",
31+
"dependencies": {
32+
"prop-types": "^15.7.2",
33+
"react-native-linear-gradient": "^2.5.6"
34+
},
35+
"author": "Soso Gvritishvili <[email protected]> (https://www.linkedin.com/in/soso-gvritishvili/)",
36+
"license": "MIT"
37+
}

src/PickerListItem.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import {View, Text} from 'react-native';
3+
4+
export default function PickerListItem({
5+
label,
6+
style,
7+
itemColor,
8+
itemsColor,
9+
fontSize,
10+
fontFamily = 'Arial',
11+
}) {
12+
return (
13+
<View style={style}>
14+
<Text
15+
style={{
16+
fontSize: fontSize,
17+
color: itemColor ? itemColor : itemsColor,
18+
fontFamily: fontFamily,
19+
}}>
20+
{label}
21+
</Text>
22+
</View>
23+
);
24+
}

src/README/.DS_Store

6 KB
Binary file not shown.

src/README/android.gif

226 KB
Loading

src/README/ios.gif

201 KB
Loading

src/index.js

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import {StyleSheet, View, ScrollView} from 'react-native';
4+
import LinearGradient from 'react-native-linear-gradient';
5+
import PickerListItem from './PickerListItem';
6+
7+
export default class DynamicallySelectedPicker extends React.Component {
8+
state = {
9+
itemHeight: this.props.height / (this.props.transparentItemRows * 2 + 1),
10+
itemIndex: this.props.initialSelectedIndex,
11+
};
12+
13+
fakeItems(n = 3) {
14+
const itemsArr = [];
15+
for (let i = 0; i < n; i++) {
16+
itemsArr[i] = {
17+
value: -1,
18+
label: '',
19+
};
20+
}
21+
return itemsArr;
22+
}
23+
24+
allItemsLength() {
25+
return this.extendedItems().length - this.props.transparentItemRows * 2;
26+
}
27+
28+
onScroll(event) {
29+
const {items, onScrollDynamicallyChange} = this.props;
30+
const tempIndex = this.getItemTemporaryIndex(event);
31+
32+
if (
33+
this.state.itemIndex !== tempIndex &&
34+
tempIndex >= 0 &&
35+
tempIndex < this.allItemsLength()
36+
) {
37+
this.setItemIndex(tempIndex);
38+
onScrollDynamicallyChange({index: tempIndex, item: items[tempIndex]});
39+
}
40+
}
41+
42+
onScrollBegin(event) {
43+
const {items, onScrollBegin} = this.props;
44+
const tempIndex = this.getItemTemporaryIndex(event);
45+
46+
if (tempIndex >= 0 && tempIndex < this.allItemsLength()) {
47+
this.setItemIndex(tempIndex);
48+
onScrollBegin({index: tempIndex, item: items[tempIndex]});
49+
}
50+
}
51+
52+
onScrollEnd(event) {
53+
const {items, onScrollEnd} = this.props;
54+
const tempIndex = this.getItemTemporaryIndex(event);
55+
56+
if (tempIndex >= 0 && tempIndex < this.allItemsLength()) {
57+
this.setItemIndex(tempIndex);
58+
onScrollEnd({index: tempIndex, item: items[tempIndex]});
59+
}
60+
}
61+
62+
getItemTemporaryIndex(event) {
63+
return Math.round(
64+
event.nativeEvent.contentOffset.y / this.state.itemHeight,
65+
);
66+
}
67+
68+
setItemIndex(index) {
69+
this.setState({
70+
itemIndex: index,
71+
});
72+
}
73+
74+
extendedItems() {
75+
const {transparentItemRows} = this.props;
76+
return [
77+
...this.fakeItems(transparentItemRows),
78+
...this.props.items,
79+
...this.fakeItems(transparentItemRows),
80+
];
81+
}
82+
83+
render() {
84+
const {itemIndex, itemHeight} = this.state;
85+
const {
86+
width,
87+
height,
88+
topGradientColors,
89+
bottomGradientColors,
90+
transparentItemRows,
91+
itemsColor,
92+
fontSize,
93+
fontFamily,
94+
selectedItemBorderColor,
95+
} = this.props;
96+
return (
97+
<View style={{height: height, width: width}}>
98+
<ScrollView
99+
showsVerticalScrollIndicator={false}
100+
showsHorizontalScrollIndicator={false}
101+
onMomentumScrollBegin={(event) => {
102+
this.onScrollBegin(event);
103+
}}
104+
onMomentumScrollEnd={(event) => {
105+
this.onScrollEnd(event);
106+
}}
107+
onScroll={(event) => {
108+
this.onScroll(event);
109+
}}
110+
scrollEventThrottle
111+
initialScrollIndex={itemIndex}
112+
snapToInterval={itemHeight}>
113+
{this.extendedItems().map((item, index) => {
114+
return (
115+
<PickerListItem
116+
key={index}
117+
label={item.label}
118+
itemColor={item.itemColor}
119+
itemsColor={itemsColor}
120+
fontSize={fontSize ? fontSize : itemHeight / 2}
121+
fontFamily={fontFamily}
122+
style={[
123+
styles.listItem,
124+
{
125+
height: itemHeight,
126+
},
127+
]}
128+
/>
129+
);
130+
})}
131+
</ScrollView>
132+
<View
133+
style={[
134+
styles.gradientWrapper,
135+
{
136+
top: 0,
137+
borderBottomWidth: 1,
138+
borderBottomColor: selectedItemBorderColor,
139+
},
140+
]}
141+
pointerEvents="none">
142+
<LinearGradient
143+
colors={topGradientColors}
144+
style={[
145+
styles.pickerGradient,
146+
{
147+
height: transparentItemRows * itemHeight,
148+
},
149+
]}
150+
/>
151+
</View>
152+
<View
153+
style={[
154+
styles.gradientWrapper,
155+
{
156+
bottom: 0,
157+
borderTopWidth: 1,
158+
borderTopColor: selectedItemBorderColor,
159+
},
160+
]}
161+
pointerEvents="none">
162+
<LinearGradient
163+
colors={bottomGradientColors}
164+
style={[
165+
styles.pickerGradient,
166+
{height: transparentItemRows * itemHeight},
167+
]}
168+
/>
169+
</View>
170+
</View>
171+
);
172+
}
173+
}
174+
175+
DynamicallySelectedPicker.defaultProps = {
176+
items: [{value: 0, label: 'No items'}],
177+
onScrollDynamicallyChange: () => {},
178+
onScrollBegin: () => {},
179+
onScrollEnd: () => {},
180+
width: 200,
181+
height: 200,
182+
initialSelectedIndex: 0,
183+
transparentItemRows: 3,
184+
itemsColor: '#000',
185+
fontFamily: 'Arial',
186+
selectedItemBorderColor: '#cecece',
187+
topGradientColors: [
188+
'rgba( 255, 255, 255, 1 )',
189+
'rgba( 255, 255, 255, 0.9 )',
190+
'rgba( 255, 255, 255, 0.7 )',
191+
'rgba( 255, 255, 255, 0.5 )',
192+
],
193+
bottomGradientColors: [
194+
'rgba( 255, 255, 255, 0.5 )',
195+
'rgba( 255, 255, 255, 0.7 )',
196+
'rgba( 255, 255, 255, 0.9 )',
197+
'rgba( 255, 255, 255, 1 )',
198+
],
199+
};
200+
201+
DynamicallySelectedPicker.propTypes = {
202+
items: PropTypes.arrayOf(
203+
PropTypes.shape({
204+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
205+
label: PropTypes.string,
206+
itemColor: PropTypes.string,
207+
}),
208+
),
209+
onScrollDynamicallyChange: PropTypes.func,
210+
onScrollBegin: PropTypes.func,
211+
onScrollEnd: PropTypes.func,
212+
initialSelectedIndex: PropTypes.number,
213+
height: PropTypes.number,
214+
width: PropTypes.number,
215+
itemsColor: PropTypes.string,
216+
selectedItemBorderColor: PropTypes.string,
217+
fontSize: PropTypes.number,
218+
fontFamily: PropTypes.string,
219+
topGradientColors: PropTypes.array,
220+
bottomGradientColors: PropTypes.array,
221+
};
222+
223+
const styles = StyleSheet.create({
224+
listItem: {
225+
alignItems: 'center',
226+
justifyContent: 'center',
227+
},
228+
gradientWrapper: {
229+
position: 'absolute',
230+
width: '100%',
231+
},
232+
pickerGradient: {
233+
width: '100%',
234+
},
235+
});

0 commit comments

Comments
 (0)