ReactNative实现的横向滑动条

OK,我们先看下效果图

注意使用到了两个库

1.react-native-linear-gradient

2.react-native-gesture-handler

ok,我们看下面的代码

import {Image, TouchableWithoutFeedback, StyleSheet, View} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import React from 'react';
import {
  Gesture,
  GestureDetector,
  GestureHandlerRootView,
} from 'react-native-gesture-handler';
export class HorizntalSlider extends React.Component {
  shouldComponentUpdate(
    nextProps: Readonly<P>,
    nextState: Readonly<S>,
    nextContext: any,
  ): boolean {
    return false;
  }
  constructor(props) {
    super(props);
    this.progress = props.initValue;
    this.step = props.step;
    this.range = props.max - props.min;
    this.currentX = 0;
    this.enable = true;
  }
  _setValueChange(value) {
    this.currentX = value;
    this.selectedTrack.setNativeProps({
      style: {width: value},
    });
    let indicatorValue = value - 5 > 0 ? value - 5 : 0;
    this.indicator.setNativeProps({
      style: {left: indicatorValue - 1},
    });
  }

  componentDidMount(): void {
    if (this.props) {
      this.setPowerState(this.props.openState);
    }
  }

  _add() {
    if (!this.enable) {
      showToast(this.tips);
      const {onEnableClick} = this.props;
      if (onEnableClick) {
        onEnableClick();
      }
      return;
    }
    let tempValue = this.progress + this.step;
    this.progress =
      tempValue > this.props.max ? this.props.max : tempValue;
    let styleValue =
      ((this.progress - this.props.min) / this.range) * 250;
    this._setValueChange(styleValue);
    const {onLastChange, onChange} = this.props;
    onChange(this.progress);
    onLastChange(this.progress);
  }

  _reduce() {
    if (!this.enable) {
      const {onEnableClick} = this.props;
      if (onEnableClick) {
        onEnableClick();
      }
      showToast(this.tips);
      return;
    }
    let tempValue = this.progress - this.step;
    this.progress =
      tempValue < this.props.min ? this.props.min : tempValue;
    let styleValue =
      ((this.progress - this.props.min) / this.range) * 250;
    this._setValueChange(styleValue);
    const {onLastChange, onChange} = this.props;
    onChange(this.progress);
    onLastChange(this.progress);
  }

  _onValueChange(x, isFinalize = false) {
    if (x > 250) {
      x = 250;
    }
    if (x < 0) {
      x = 0;
    }
    this.currentX = x;
    this.progress = this.props.min + parseInt((x / 250) * this.range);
    // if (isFinalize) {
    //   const {onLastChange} = this.props;
    //   onLastChange(this.progress);
    // } else {
    //   const {onChange} = this.props;
    //   onChange(this.progress);
    // }
    this._setValueChange(x);
  }

  setPowerState(state) {
    if (!this.props) {
      return;
    }
    if (state === 1) {
      this.selectedTrack.setNativeProps({
        style: {
          width: this.currentX,
        },
      });
      this.indicator.setNativeProps({
        style: {opacity: 1},
      });
    } else {
      this.selectedTrack.setNativeProps({
        style: {width: 0},
      });
      this.indicator.setNativeProps({
        style: {opacity: 0},
      });
    }
  }

  setEnable(isEnable, tips) {
    if (!this.props) {
      return;
    }
    this.enable = isEnable;
    this.tips = tips;
  }

  gesture = Gesture.Pan()
    .onBegin(e => {
      this._onValueChange(e.x);
    })
    .onUpdate(e => {
      this._onValueChange(e.x);
    })
    .onFinalize(e => {
      this._onValueChange(e.x, true);
    });

  render() {
    this.currentX = ((this.progress - this.props.min) / this.range) * 250;
    this.currentX = this.currentX > 0 ? this.currentX : 0;
    return (
      <View style={[styles.mainContainer, this.props.style]}>
        <GestureHandlerRootView>
          <GestureDetector gesture={this.gesture}>
            <View style={styles.sliderContainer}>
              <LinearGradient
                start={{x: 0, y: 0}}
                end={{x: 1, y: 0}}
                colors={['#4372FF', 'white', '#FF4D4F']}
                style={{
                  width: 252,
                  height: 60,
                }}
              />
              <View
                style={{
                  flexDirection: 'row',
                  alignItems: 'center',
                  position: 'absolute',
                }}>
                <View
                  ref={c => (this.selectedTrack = c)}
                  style={{
                    width: this.currentX,
                    opacity: 0,
                    height: 60,
                  }}
                />
                <View
                  style={{
                    flex: 1,
                    backgroundColor: '#12161a',
                    opacity: 0.8,
                    height: 60,
                  }}
                />
              </View>
              <View
                ref={c => (this.indicator = c)}
                style={[styles.indicator, {left: this.currentX - 7}]}
              />
            </View>
          </GestureDetector>
        </GestureHandlerRootView>
      </View>
    );
  }
}

class Track extends React.Component {
  constructor(props) {
    super(props);
    this.unitViewArr = [];
    for (let i = 0; i < 42; i++) {
      this.unitViewArr[i] = i;
    }
  }
  shouldComponentUpdate(
    nextProps: Readonly<P>,
    nextState: Readonly<S>,
    nextContext: any,
  ): boolean {
    return false;
  }

  render() {
    return (
      <View style={styles.trackContainer}>
        {this.unitViewArr.map((item, index) => {
          return (
            <View
              key={index}
              style={{flexDirection: 'row', alignItems: 'center'}}>
              <View
                style={{
                  height: 60,
                  width: 2,
                  opacity: 0,
                  backgroundColor: '#12161a',
                  borderRadius: 100,
                }}
              />
              <View
                style={{height: 60, width: 4, backgroundColor: '#12161a'}}
              />
            </View>
          );
        })}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  mainContainer: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  sliderContainer: {
    position: 'relative',
    justifyContent: 'center',
    paddingVertical: 10,
    marginLeft: 10,
    marginRight: 8,
  },
  trackContainer: {
    width: 252,
    flexDirection: 'row',
    position: 'absolute',
  },
  actionImg: {
    width: 60,
    height: 60,
  },
  thumb: {
    height: 34,
    width: 7,
    backgroundColor: 'transparent',
  },
  indicator: {
    width: 0,
    height: 0,
    position: 'absolute',
    top: -2,
    borderLeftWidth: 4,
    borderTopWidth: 4,
    borderRightWidth: 4,
    left: -3,
    borderTopColor: '#FF6A6B',
    borderLeftColor: 'transparent',
    borderRightColor: 'transparent',
  },
});
export default HorizntalSlider;

使用代码如下

        <GestureHandlerHorizntalSlider
              model={{
                initValue: 20,
                step: 10,
                max: 100,
                min: 0,
              }}>
       </GestureHandlerHorizntalSlider>

拖动条:max(最大值),min(最小值),initValue(当前值),step(步调)

相关推荐
爱lv行3 天前
生态:React Native
javascript·react native·react.js
少恭写代码5 天前
duxapp 2024-12-18更新 新增 Svg 组件 Tab 支持幻灯片切换功能
react native·小程序·taro
凌鲨6 天前
React Native学习路线图
学习·react native·react.js
一个处女座的程序猿O(∩_∩)O6 天前
四大跨平台开发框架深度解析——uniapp、uniapp-X、React Native与Flutter
flutter·react native·uni-app
苍岚丨晨苏6 天前
使用Taro开发iOS App触发额外权限请求的问题
react native·taro
Domain-zhuo8 天前
如何理解React State不可变性的原则
前端·javascript·react native·react.js·前端框架·ecmascript
wuwuFQ10 天前
React Native状态管理器Redux、MobX、Context API、useState
javascript·react native·react.js
爱lv行11 天前
创建 React Native 项目
javascript·react native·react.js
某柚啊11 天前
Hermes engine on React Native 0.72.5,function无法toString转成字符串
javascript·react native·react.js
Domain-zhuo12 天前
React的功能是什么?
前端·javascript·react native·react.js·前端框架·ecmascript