Skip to content

Commit 3be6676

Browse files
Merge pull request #68 from githuboftigran/v2
V2
2 parents 8433426 + f56a9dd commit 3be6676

28 files changed

Lines changed: 494 additions & 2265 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Default ignored files
2+
.idea/*

.idea/.gitignore

Lines changed: 0 additions & 8 deletions
This file was deleted.

LabelContainer.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React, { PureComponent } from 'react';
2+
import { View } from 'react-native';
3+
4+
class LabelContainer extends PureComponent {
5+
6+
state = {
7+
value: Number.NaN,
8+
};
9+
10+
setValue = value => {
11+
this.setState({ value });
12+
}
13+
14+
render() {
15+
const { renderContent, ...restProps } = this.props;
16+
const { value } = this.state;
17+
return (
18+
<View {...restProps}>
19+
{renderContent(value)}
20+
</View>
21+
);
22+
}
23+
}
24+
25+
export default LabelContainer;

README.md

Lines changed: 63 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,90 @@
11
# RangeSlider
2-
A fully customizable high quality react native Slider component backed by custom native iOS and Android views with ability to select range of values.
2+
A highly optimized and fully customizable pure JS component for value range selection.
33

4-
<p align="center">
5-
<img src="https://raw.githubusercontent.com/githuboftigran/rn-range-slider/master/demo.gif" width="298" height="176">
6-
</p>
4+
The component is not re-rendered while user moves the thumb.<br/>
5+
Even if there is a label, only the label component is re-rendered when values are changed.
6+
7+
RangeSlider uses React Native's Animated library to transform thumbs / label / selected rail.<br/>
8+
These optimizations help to achieve as much native look & feel as possible using only the JS layer.
79

810
<p align="center">
9-
<a href="https://github.com/githuboftigran/rn-widgets-demo">Demo app</a>
11+
<img src="https://raw.githubusercontent.com/githuboftigran/rn-range-slider/master/demo.gif" width="369" height="195">
1012
</p>
1113

12-
## Installation
13-
14-
1. Add
14+
#### Version 1
15+
The version 1 was using native Android and iOS views.<br/>
16+
That gives native look & feel in favor of flexibility.<br/>
17+
You can find the version 1 [here](https://github.com/githuboftigran/rn-range-slider/tree/v1).
1518

16-
* npm: `npm install --save rn-range-slider`
17-
* yarn: `yarn add rn-range-slider`
18-
19-
2. Linking
20-
21-
##### For older React native versions ( < 0.60 ) you need to link the library:
22-
23-
- Run `react-native link rn-range-slider`
24-
- If linking fails, follow the
25-
[manual linking steps](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking)
19+
## Installation
2620

27-
##### For newer React native versions ( >= 0.60 ) you need to install pods for iOS:
28-
- cd ios && pod install && cd ..
29-
- For android everything works out of the box
21+
* npm: `npm install --save rn-range-slider`
22+
* yarn: `yarn add rn-range-slider`
3023

3124
## Usage
3225

33-
```RangeSlider``` should have fixed width and height.
26+
RangeSlider uses react hooks, so this component doesn't work with React Native versions below 0.59.0
3427

3528
```
36-
import RangeSlider from 'rn-range-slider';
37-
3829
...
3930
40-
<RangeSlider
41-
style={{width: 160, height: 80}}
42-
gravity={'center'}
43-
min={200}
44-
max={1000}
45-
step={20}
46-
selectionColor="#3df"
47-
blankColor="#f618"
48-
onValueChanged={(low, high, fromUser) => {
49-
this.setState({rangeLow: low, rangeHigh: high})
50-
}}/>
51-
/>
31+
import RangeSlider from 'rn-range-slider';
5232
5333
...
54-
```
55-
56-
### Properties
57-
58-
Supported color formats are: **#RGB**, **#RGBA**, **#RRGGBB**, **#RRGGBBAA**
59-
60-
61-
| Name | Description | Type | Default Value |
62-
|----------|-----------------------|------|:-------------:|
63-
| disabled | If true user won't be able to move the slider | Boolean | **false** |
64-
| rangeEnabled | Slider works as an ordinary slider with 1 control if false | Boolean | **true** |
65-
| valueType | Type of slider values | String<br/><br/>Currently supported values:<br/>- **number**<br/>- **time** | **number** |
66-
| lineWidth | Width of slider's line | Number | **4** |
67-
| thumbRadius | Radius of thumb (including border) | Number | **10** |
68-
| thumbBorderWidth | Border width of thumb | Number | **2** |
69-
| textSize | Size of label text | Number | **16** |
70-
| labelBorderWidth | Border width of label | Number | **2** |
71-
| labelPadding | Padding of label (distance between border and text) | Number | **4** |
72-
| labelBorderRadius | Border radius of label bubble | Number | **4** |
73-
| labelTailHeight | Height of label bubble's tail | Number | **8** |
74-
| labelGapHeight | Gap between label and slider | Number | **4** |
75-
| textFormat | This string will be formatted with active value and shown in thumb.<br/>If `valueType` is set to **time** this prop will be considered as date formatter.<br/>Since this library uses native components and everything is rendered at native side, time on label text will be formatted by [`NSDateFormatter`](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html) for iOS and [`SimpleDateFormat`](https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html) for Android, so make sure you are passing valid format for both platforms. | String<br/>**"Price: %d**" =><br/>"**Price: 75**"<br/>if the current value is 75 | **%d**<br/> (just the number) |
76-
| labelStyle | Style of the label.<br/>Label is not shown if **none** | String<br/><br/>Currently supported values:<br/>- **none**<br/>- **bubble** | **bubble** |
77-
| gravity | Vertical gravity of drawn content | String<br/><br/>Currently supported values:<br/>- **top**<br/>- **bottom**<br/>- **center** | **top** |
78-
| selectionColor | Color of selected part | String | **#4286f4** |
79-
| blankColor | Color of unselected part | String | **#ffffff7f** |
80-
| thumbColor | Color of thumb | String | **#ffffff** |
81-
| thumbBorderColor | Color of thumb's border | String | **#cccccc** |
82-
| labelBackgroundColor | Color label's background | String | **#ff60ad** |
83-
| labelBorderColor | Color label's border | String | **#d13e85** |
84-
| labelTextColor | Color label's text | String | **#ffffff** |
85-
| step | Step of slider. If `valueType` is set to **time**, this prop wil considered as milliseconds. | Number | **1** |
86-
87-
Props below may have different types depending on `valueType` prop.<br/>
88-
If `valueType` is set to **number**, these props should be `Number`s (integer).<br/>
89-
If `valueType` is set to **time**, these props may be `Number` (integer) or `Date` and if a `Number` is passed the value will be considered as timestamp.
90-
91-
| Name | Description | Type | Default Value |
92-
|----------|-----------------------|------|:-------------:|
93-
| min | Minimum value of slider | Depends on `valueType` | **0** |
94-
| max | Maximum value of slider | Depends on `valueType` | **100** |
95-
| initialLowValue | Initial value of lower thumb | Depends on `valueType` | **0** |
96-
| initialHighValue | Initial value of higher thumb | Depends on `valueType` | **100** |
97-
98-
<br/>
99-
100-
If `initialLowValue` ( or `initialHighValue`) is not provided, it's set to `min` (or `max`).
10134
102-
### Methods
35+
const renderThumb = useCallback(() => <Thumb/>, []);
36+
const renderRail = useCallback(() => <Rail/>, []);
37+
const renderRailSelected = useCallback(() => <RailSelected/>, []);
38+
const renderLabel = useCallback(value => <Label text={value}/>, []);
39+
const renderNotch = useCallback(() => <Notch/>, []);
40+
const handleValueChange = useCallback((low, high) => {
41+
setLow(low);
42+
setHigh(high);
43+
}, []);
10344
104-
To call methods of ```RangeSlider``` you need to have a reference to it's instance.<br/>
105-
React native provides 2 ways to do it:
106-
107-
```
108-
...
109-
<RangeSlider ref="_rangeSlider" />
11045
...
111-
this.refs._rangeSlider.setLowValue(42);
112-
...
113-
```
11446
115-
or
47+
<Slider
48+
style={styles.slider}
49+
min={0}
50+
max={100}
51+
step={1}
52+
floatingLabel
53+
renderThumb={renderThumb}
54+
renderRail={renderRail}
55+
renderRailSelected={renderRailSelected}
56+
renderLabel={renderLabel}
57+
renderNotch={renderNotch}
58+
onValueChanged={handleValueChange}
59+
/>
11660
117-
```
118-
...
119-
<RangeSlider ref={ component => this._rangeSlider = component } />
120-
...
121-
this._rangeSlider.setLowValue(42);
12261
...
12362
```
12463

125-
#### Available methods
126-
127-
| Name | Description | Params |
128-
|---|---|---|
129-
| setLowValue | Set low value of slider | value: `Number` (or Date, if `valueType` is set to **time**) |
130-
| setHighValue | Set high value of slider | value: `Number` (or Date, if `valueType` is set to **time**) |
131-
132-
### Callbacks
133-
134-
| Name | Description | Params |
135-
|----------|---------------------|--------|
136-
| onValueChanged | A callback to be called when value was changed.<br/><br/>Type of _lowValue_ and _highValue_ will be `Number` if `valueType` is **number** and `Date` if `valueType` is **time**<br/><br/>_fromUser_ parameter is true if the value was changed because of user's interaction (not by calling __setLowValue__ or __setHighValue__ methods). Just like android's [OnSeekbarChangeListener](https://developer.android.com/reference/android/widget/SeekBar.OnSeekBarChangeListener). | lowValue: number<br/><br/>highValue: number<br/><br/>fromUser: boolean |
137-
| onTouchStart | Nothing to explain I think :) | - |
138-
| onTouchEnd | Nothing to explain here too | - |
64+
### Properties
13965

14066

141-
## Known issues
142-
* Label's corner radius is not working on iOS
143-
* Problems with expo (won't fix as I don't take Expo seriously)
67+
| Name | Description | Type | Default Value |
68+
| --- | --- | --- | :-------------: |
69+
| `min` | Minimum value of slider | number | _**required**_ |
70+
| `max` | Maximum value of slider | number | _**required**_ |
71+
| `step` | Step of slider | number | `1` |
72+
| `low` | Low value of slider | number | Initially `min` value will be set if not provided |
73+
| `high` | High value of slider | number | Initially `max` value will be set if not provided |
74+
| `floatingLabel` | If set to `true`, labels will not take space in component tree. Instead they will be rendered over the content above the slider (like a small popup). | boolean | `false` |
75+
| `disableRange` | Slider works as an ordinary slider with 1 control if `true` | boolean | `false` |
76+
| `allowLabelOverflow` | If set to `true`, labels are allowed to be drawn outside of slider component's bounds.<br/>Otherwise label's edges will never get out of component's edges. | boolean | `false` |
77+
| `renderThumb` | Should render the thumb. | `() => Node` | _**required**_ |
78+
| `renderRail` | Should render the "rail" for thumbs.<br/>Rendered component **should** have `flex: 1` style so it won't fill up the whole space. | `() => Node` | _**required**_ |
79+
| `renderRailSelected` | Should render the selected part of "rail" for thumbs.<br/>Rendered component **should not** have `flex: 1` style so it fills up the whole space. | `() => Node` | _**required**_ |
80+
| `renderLabel` | Should render label above thumbs.<br/>If no function is passed, no label will be drawn. | `(value: number) => Node` | `undefined` |
81+
| `renderNotch` | Should render the notch below the label (above the thumbs).<br/>Classic notch is a small triangle below the label.<br/>If `allowLabelOverflow` is not set to true, the notch will continue moving with thumb even if the label has already reached the edge of the component and can't move further.| `() => Node` | `undefined` |
82+
| `onValueChanged` | Will be called when a value was changed.<br/>If `disableRange` is set to true, the second argument should be ignored. | `(low: number, high: number) => void` | `undefined` |
83+
84+
## A special section about permanent labels.
85+
86+
The label of active thumb is a hint for a user. It's not showing selected values permanently.
87+
It's a bad UI and UX to have a data for user in a moving label.
88+
If you need to show current selected values to the user, add Text components to some static place in the screen and set the text based on selected low and high values.
89+
I didn't and won't add that functionality to this component.
90+
Any issues about this will be closed immediately.

android/build.gradle

Lines changed: 0 additions & 34 deletions
This file was deleted.

android/src/main/AndroidManifest.xml

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)