Search code examples
javascriptreact-nativeexporangeslider

Range slider in React Native


I'm trying to figure out how to add those 'prefixes'. Do I need to handle it through styling manually, or is there a specific prop I should be using? I'm still getting the hang of it, so any guidance would be greatly appreciated

this is the figma design that i want to develop

I'am using '@ptomasroos/react-native-multi-slider' library

And this is the component of the range slider:

import MultiSlider from '@ptomasroos/react-native-multi-slider';
import React, { useEffect, useState } from 'react';
import { Dimensions, StyleSheet, Text, View } from 'react-native';

export default function RangeNumber({ onChange}) {
    const [value, setValue] = useState({ values: [0, 800000] });
    const multiSliderValuesChange = (values) => {
        setValue({
            values,
        });
    };
    useEffect(() => {
        onChange(value)
    }, [value])
    return (
        <View style={styles.container}>
            <MultiSlider
                values={[value.values[0], value.values[1]]}
                sliderLength={Dimensions.get('window').width * 0.83}
                selectedStyle={{ backgroundColor: Colors.DeepGreen }}
                // containerStyle={{
                //     justifyContent: 'center',
                //     alignItems: 'center'
                // }}
                onValuesChange={multiSliderValuesChange}
                markerStyle={{
                    height: 30,
                    width: 30,
                    borderWidth: 7,
                    borderRadius: 50,
                    backgroundColor: Colors.DeepGreen,
                    borderColor: Colors.white,
                }}
                trackStyle={{
                    height: 10,
                }}
                unselectedStyle={{
                    borderRadius: 10
                }}
                min={0}
                markerOffsetY={5}
                max={800000}
                step={100}

            />
            <View style={styles.rangeText}>
                <Text style={styles.textColor}>{value.values[0]} K</Text>
                <Text style={styles.text}> - </Text>
                <Text style={styles.textColor}>{value.values[1]} K</Text>
            </View>
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        alignItems: 'flex-start',
        justifyContent: 'center',
        paddingHorizontal: 15,
        paddingVertical: 5,

    },
    title: {
        fontSize: 16,
        fontFamily: FONTS.PoppinsSemiBold
    },
    text: {
        color: '#FFFFFF',
        fontSize: 20,
        marginHorizontal: 10,
        marginTop: 10
    },
    rangeText: {
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
        marginTop: -20
    },
    textColor: {
        color: '#DBDBDB',
        fontSize: 20
    }
});

this is the slider i got


Solution

  • You will have to style manually. Ideally the custom label prop should do this Job but I can't seem to get it to work either.

    I have managed to create a basic example that outputs like so:

    Example Screenshot

    Code:

    import React from "react";
    
    import { StyleSheet, View, Text, Image } from "react-native";
    import MultiSlider from "@ptomasroos/react-native-multi-slider";
    
    export default function App() {
      const [multiSliderValue, setMultiSliderValue] = React.useState([0, 100]);
    
      nonCollidingMultiSliderValuesChange = (values) => setMultiSliderValue(values);
    
      return (
        <View style={styles.container}>
          <Text style={styles.title}>Sliders</Text>
    
          <View style={styles.sliderOne}>
            <Text style={styles.text}>
              Two Markers with minimum overlap distance:
            </Text>
          </View>
          <MultiSlider
            values={[multiSliderValue[0], multiSliderValue[1]]}
            sliderLength={280}
            onValuesChange={nonCollidingMultiSliderValuesChange}
            min={0}
            max={100}
            step={1}
            allowOverlap={false}
            snapped
            minMarkerOverlapDistance={40}
            customMarkerLeft={(e) => {
              return <CustomMarker currentValue={e.currentValue} />;
            }}
            customMarkerRight={(e) => {
              return <CustomMarker currentValue={e.currentValue} />;
            }}
            isMarkersSeparated={true}
          />
        </View>
      );
    }
    
    const CustomMarker = ({ currentValue }) => {
      return (
        <View
          style={{
            transform: [{ rotate: "90deg" }],
          }}
        >
          <View
            collapsable={false}
            style={{
              marginLeft: 54,
              marginBottom: -32,
              width: 15,
              height: 15,
              borderRadius: 10,
              backgroundColor: "blue",
            }}
          ></View>
          <View
            style={{
              width: 40,
              height: 50,
              backgroundColor: "#146f79",
              borderRadius: 10,
              padding: 5,
              position: "relative",
              marginRight: 80,
              transform: [{ rotate: "180deg" }],
            }}
          >
            <Text
              style={{
                width: "100%",
                textAlign: "right",
                transform: [{ rotate: "90deg" }],
                color: "#fff",
              }}
            >
              {currentValue}
            </Text>
            <View
              style={{
                position: "absolute",
                left: -10,
                top: 25,
                width: 0,
                height: 0,
                backgroundColor: "transparent",
                borderStyle: "solid",
                borderRightWidth: 10,
                borderTopWidth: 10,
                borderRightColor: "transparent",
                borderTopColor: "#146f79",
                transform: [{ rotate: "90deg" }],
              }}
            />
            <View
              style={{
                position: "absolute",
                left: -10,
                top: 15,
                width: 0,
                height: 0,
                backgroundColor: "transparent",
                borderStyle: "solid",
                borderRightWidth: 10,
                borderTopWidth: 10,
                borderRightColor: "transparent",
                borderTopColor: "#146f79",
                transform: [{ rotate: "180deg" }],
              }}
            />
          </View>
        </View>
      );
    };
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        flexDirection: "column",
        justifyContent: "center",
        alignItems: "center",
      },
      sliders: {
        margin: 20,
        width: 280,
      },
      text: {
        alignSelf: "center",
        paddingVertical: 20,
      },
      title: {
        fontSize: 30,
      },
      sliderOne: {
        flexDirection: "row",
        justifyContent: "space-around",
        marginBottom: 50,
      },
      image: {
        height: 40,
        width: 40,
      },
    });
    

    The code uses the custom marker that renders a "Floating" component above the marker to display the value. The floating component is made of three views, one bubble to display the value then two triangles to display the pointer.

    Hope this helps or at least gives you a starting point.