0

I need to do the following implementation in React Native: http://jsfiddle.net/t8mzLuh4/3/

But I can't think of the most optimal way to do it, I have tried different ways, but they have not been optimal.

I am trying to implement a screen where there are 3 sliders, and I want to make the combined total of the 3 sliders never go over the maximum.

I don't care how it is implemented, it can be from a starting 0, and as soon as I change 1 slider, the remaining total available decreases or putting a slider beyond the maximum, decreases the values on the other sliders.

This is my current implementation of the slider with reanimated 2

const Slider = ({
  label,
  min,
  value,
  labelAmount,
  colorAmount,
  max,
  currency,
  onChange,
  step,
}: SliderProps) => {
  const isActive = useSharedValue(false);
  const translationX = useSharedValue(((width - PADDING * 2) * 0) / max);
  const amount = useSharedValue(value);
  const formattedAmount = useSharedValue(
    formatAsMoney(value, currency ?? '$')
  );

  const wrapper = (value: number) => {
    formattedAmount.value = formatAsMoney(value, currency ?? '$');
  };

  useDerivedValue(() => {
    runOnJS(wrapper)(amount.value);
  });

  const onSelect = (value: number) => {
    'worklet';
    runOnJS(onChange)(value);
  };

  const onGestureEvent = useAnimatedGestureHandler({
    onStart: () => {
      isActive.value = true;
    },
    onActive: (event) => {
      translationX.value = interpolate(
        event.x,
        [0, width],
        [0 - RADIUS, width - PADDING],
        Extrapolate.CLAMP
      );
      amount.value =
        Math.ceil(
          interpolate(
            translationX.value,
            [0 - RADIUS, width - PADDING * 2 + RADIUS],
            [min, max],
            Extrapolate.CLAMP
          ) / step
        ) * step;
    },
    onEnd: () => {
      isActive.value = false;
      onSelect(amount.value);
    },
  });

  const transform = useAnimatedStyle(() => {
    const translateX = translationX.value;
    return {
      transform: [
        { translateX },
        { scale: withSpring(isActive.value ? 1 : 0.75) },
      ],
    };
  });

  const barWidth = useAnimatedStyle(() => {
    return {
      width: translationX.value + RADIUS,
    };
  });
  return (
    <View>
      <View
        style={{ 
         flexDirection: "row",
         justifyContent="space-between",
         alignItems="center" 
       }}
      >
        <Text>
          {label}
        </Text>
        <ReText
          text={formattedAmount}
          style={[
            styles.text,
            {
              fontSize: labelAmount === 'small' ? 18 : 22,
              color: '#000',
            },
          ]}
        />
      </View>
      <View style={styles.shadow}>
        <View style={styles.container}>
          <View style={styles.barContainer}>
            <View
              style={[
                styles.bar,
                {
                  backgroundColor: '#fff',
                },
              ]}
            />
            <Animated.View
              style={[
                styles.bar,
                {
                  backgroundColor: 'green',
                },
                barWidth,
              ]}
            />
          </View>

          <PanGestureHandler {...{ onGestureEvent }}>
            <Animated.View
              style={[
                StyleSheet.absoluteFillObject,
                {
                  marginHorizontal: PADDING / 2,
                },
              ]}
            >
              <Animated.View
                style={[styles.cursor, transform, styles.shadow]}
              />
            </Animated.View>
          </PanGestureHandler>
        </View>
        <View
          style={{
          alignSelf: "flex-start",
          flexDirection: "row",
          justifyContent: "space-between",
          alignItems: "center",
          width: "100%"
          }}
        >
          <Text >
            {formatAsMoney(min, currency ?? '$')}
          </Text>
          <Text>
            {formatAsMoney(max, currency ?? '$')}
          </Text>
        </View>
      </View>
    </View>
  );
};

const useStyles = StyleSheet.create({
  shadow: {
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 3.84,
    elevation: 5,
    alignItems: 'center',
  },
  container: {
    height: HEIGHT,
    width: width,
    alignItems: 'center',
    justifyContent: 'center',
  },

  barContainer: {
    height: BAR_HEIGHT,
    width: width - PADDING,
  },
  bar: {
    borderRadius: BORDER_RADIUS,
    ...StyleSheet.absoluteFillObject,
  },

  cursor: {
    height: RADIUS * 2,
    width: RADIUS * 2,
    borderRadius: RADIUS,
    backgroundColor: 'white',
  },

  text: {
    fontWeight: '700',
  },


0 Answers0