如何在react-native-slider

时间:2017-07-10 16:33:19

标签: reactjs animation react-native react-native-android

我有一个非常大量编辑的react-native-slider版本,用于创建带有自定义图像的滑块。到目前为止,我有一个背景图像,其中两个图像作为滑块的拇指,但我想应用动画' onSlidingComplete'其中一个图像。

请注意,我已经编辑了node_modules中的slider.js文件以获得我想要的效果,并且我已经设法让一切工作到现在为止但我不能为我的生活做任何动画工作。

滑块声明:

             <Slider

                style={styles.slider}

                trackStyle={styles.trackStyle}

                maximumValue={this.props.max}

                minimumValue={this.props.min}

                step={this.props.step}

                value={this.state.value}

                thumbTouchSize={this.props.thumbTouchSize}

                sliderBg={require('../../images/tank_bg.png')}

                thumbImage={require('../../images/thumb_slider.png')}

                thumbImageBg={require('../../images/thumb_slider_whitebg_line.png')}

                onSlidingComplete={(value) => this.onSlidingComplete(value)}

                onValueChange={(value) => this.onValueChange(value)}

                orientation={'horizontal'}

                sliderAnim={this.state.sliderAnim}

            />

这就是我设置slider.js的方法。

我已经尝试实现动画的地方是第577行的_setCurrentValueAnimated函数和第240行的_animateSlider函数。

我要做的是通过声明将一个布尔值传递给滑块,作为this.state.sliderAnim:proptypes.bool,然后让代码执行一个脚本动画。

我想要做的就是每次调用onSlidingComplete时,使thumbImageBg的动画高度从0到100%。

任何帮助都很受欢迎

                    `
        import React, {
          Component,
        } from "react";
        import {
          Animated,
          StyleSheet,
          Image,
          PanResponder,
          View,
          Easing,
          Dimensions,
          LayoutAnimation,
          TouchableWithoutFeedback,
          TouchableOpacity,
          Platform,
          UIManager
        } from "react-native";

        import PropTypes from 'prop-types';

        if (Platform.OS === 'android') {
          UIManager.setLayoutAnimationEnabledExperimental(true);
        };

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~

删除了许多不必要的代码以适应30k最大字符大小。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~

          state = {
            containerSize: {width: 0, height: 0},
            trackSize: {width: 0, height: 0},
            thumbSize: {width: 0, height: 0},
            allMeasured: false,
            value: new Animated.Value(this.props.value),
            imageBGStyle: {
              height: this.props.thumbImageBg.height,
            }
          };

          static defaultProps = {
            value: 0,
            minimumValue: 0,
            maximumValue: 1,
            step: 0,
            minimumTrackTintColor: '#3f3f3f',
            maximumTrackTintColor: '#b3b3b3',
            thumbTintColor: '#343434',
            thumbTouchSize: {width: 80, height: 80},
            debugTouchArea: true,
            animationType: 'timing',
            orientation: 'horizontal',
            sliderAnim: true,
          };

          _animateSlider() { // #################################################################
            // I USED THIS METHOD TO TRY CREATE AN ANIMATION USING LAYOUTANIMATION
            LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
            this.setState({
              imageBGStyle: {
                height: '100%',
              }
            })
            LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
            setInterval(function() {this.setState({
              imageBGStyle: {
                height: '0%',
              }
            })}.bind(this),5000)
          }

          componentWillMount() {
            this._panResponder = PanResponder.create({
              onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
              onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
              onPanResponderGrant: this._handlePanResponderGrant,
              onPanResponderMove: this._handlePanResponderMove,
              onPanResponderRelease: this._handlePanResponderEnd,
              onPanResponderTerminationRequest: this._handlePanResponderRequestEnd,
              onPanResponderTerminate: this._handlePanResponderEnd,
            });

            if(this.sliderAnim == true)
            {
              this.animatedValue = new Animated.Value(100);
              alert('sliderAnim is true and runs');
              console.log('sliderAnim is true and runs');
            }
          };

          componentWillReceiveProps(nextProps) {
            var newValue = nextProps.value;

            if (this.props.value !== newValue) {
              if (this.props.animateTransitions) {
                this._setCurrentValueAnimated(newValue);
              }
              else {
                this._setCurrentValue(newValue);
              }
            }
          };

          render() {
            var {
              minimumValue,
              maximumValue,
              minimumTrackTintColor,
              maximumTrackTintColor,
              thumbTintColor,
              thumbImage,
              styles,
              style,
              trackStyle,
              thumbStyle,
              debugTouchArea,
              orientation,
              sliderBg,
              thumbImageBg,
              sliderAnim,
              ...other
            } = this.props;
            var {value, containerSize, trackSize, thumbSize, allMeasured} = this.state;
            var mainStyles = styles || defaultStyles;
            var outputRange;
            if (orientation === 'horizontal') {
              outputRange = [0, containerSize.width - thumbSize.width];
            } else {
              outputRange = [containerSize.height - thumbSize.height, 0];
            }
            var thumbStart = value.interpolate({
                inputRange: [minimumValue, maximumValue],
                outputRange: outputRange,
                //extrapolate: 'clamp',
              });
            var valueVisibleStyle = {};
            if (!allMeasured) {
              valueVisibleStyle.opacity = 0;
            }

            var minimumTrackStyle = {
              position: 'absolute',
              // width: Animated.add(thumbStart, thumbSize.width/2),
              backgroundColor: minimumTrackTintColor,
              ...valueVisibleStyle
            };

            if (orientation === 'horizontal') {
              minimumTrackStyle.width = Animated.add(thumbStart, thumbSize.width / 2);
              minimumTrackStyle.marginTop = -trackSize.height;
            } else {
              minimumTrackStyle.marginLeft = -trackSize.width;
              minimumTrackStyle.top = thumbStart;
              minimumTrackStyle.height = Animated.add(thumbStart, -trackSize.height);
              minimumTrackStyle.height = Animated.multiply(minimumTrackStyle.height, -1);
            }

            var touchOverflowStyle = this._getTouchOverflowStyle();

            let imageBGStyle = [defaultStyles.thumbImgStyleBg, this.state.imageBGStyle];

            return (
              <View {...other} style={[mainStyles.container, style]} onLayout={this._measureContainer}>
                <Image style={defaultStyles.trackImgStyle} source={this.props.sliderBg}>
                  <View
                    style={[{backgroundColor: maximumTrackTintColor,}, mainStyles.track, trackStyle]}
                    renderToHardwareTextureAndroid={true}
                    onLayout={this._measureTrack} />

                    {/*LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);*/}

                  {/*<Animated.View
                    renderToHardwareTextureAndroid={true}
                    style={[mainStyles.track, trackStyle, minimumTrackStyle]} >
                    </Animated.View>*/}

                    {/*<TouchableOpacity
                      style={[defaultStyles.touchArea, {zIndex: 100}]}
                      onPress={this.animateSlider.bind(this)}>*/}

                  <Animated.View
                    onLayout={this._measureThumb}
                    renderToHardwareTextureAndroid={true}
                    style={[

                      mainStyles.thumb, thumbStyle,
                      {
                        transform: [
                          { translateX: thumbStart },
                          { translateY: 0 }
                        ],
                        ...valueVisibleStyle
                      }
                    ]} 
                  >


                      <Animated.Image 
                      style={imageBGStyle} 
                      source={this.props.thumbImageBg} >
                        <Animated.Image 
                        style={defaultStyles.thumbImgStyle} 
                        source={this.props.thumbImage}/>
                      </Animated.Image>
                  </Animated.View>
                    {/*</TouchableOpacity>*/}


                  <View
                    renderToHardwareTextureAndroid={true}
                    style={[defaultStyles.touchArea, touchOverflowStyle]}
                    {...this._panResponder.panHandlers}>
                    {debugTouchArea == true && this._renderDebugThumbTouchRect(thumbStart)}
                  </View>
                </Image>
              </View>
            );
          };

          _animate() { 
            Animated.timing(this.animatedValue,
            {
              toValue: 50,
              duration: 5000,
              easing: Easing.bounce
            }).start()
          };

          _getPropsForComponentUpdate(props) {
            var {
              value,
              onValueChange,
              onSlidingStart,
              onSlidingComplete,
              style,
              trackStyle,
              thumbStyle,
              ...otherProps,
            } = props;

            return otherProps;
          };

          _handleStartShouldSetPanResponder = (e: Object, /*gestureState: Object*/): boolean => {
            // Should we become active when the user presses down on the thumb?
            return this._thumbHitTest(e);
          };

          _handleMoveShouldSetPanResponder(/*e: Object, gestureState: Object*/): boolean {
            // Should we become active when the user moves a touch over the thumb?
            return false;
          };

          _handlePanResponderGrant = (/*e: Object, gestureState: Object*/) => {
            this._previousStart = this._getThumbStart(this._getCurrentValue());
            this._fireChangeEvent('onSlidingStart');
          };
          _handlePanResponderMove = (e: Object, gestureState: Object) => {
            if (this.props.disabled) {
              return;
            }

            this._setCurrentValue(this._getValue(gestureState));
            this._fireChangeEvent('onValueChange');
          };
          _handlePanResponderRequestEnd(e: Object, gestureState: Object) {
            // Should we allow another component to take over this pan?
            return false;
          };
          _handlePanResponderEnd = (e: Object, gestureState: Object) => {
            if (this.props.disabled) {
              return;
            }


            console.log("holy fuck");

            this._setCurrentValue(this._getValue(gestureState));
            this._fireChangeEvent('onSlidingComplete');
            if(this.sliderAnim === true)
            {
              this._animateSlider();
            }
          };

          onSlidingComplete() {
            alert("nah this works!");
          }

          _measureContainer = (x: Object) => {
            this._handleMeasure('containerSize', x);
          };

          _measureTrack = (x: Object) => {
            this._handleMeasure('trackSize', x);
          };

          _measureThumb = (x: Object) => {
            this._handleMeasure('thumbSize', x);
          };

          _handleMeasure = (name: string, x: Object) => {
            var {width, height} = x.nativeEvent.layout;
            var size = {width: width, height: height};

            var storeName = `_${name}`;
            var currentSize = this[storeName];
            if (currentSize && width === currentSize.width && height === currentSize.height) {
              return;
            }
            this[storeName] = size;

            if (this._containerSize && this._trackSize && this._thumbSize) {
              this.setState({
                containerSize: this._containerSize,
                trackSize: this._trackSize,
                thumbSize: this._thumbSize,
                allMeasured: true,
              })
            }
          };

          _getRatio = (value: number) => {
            return (value - this.props.minimumValue) / (this.props.maximumValue - this.props.minimumValue);
          };

          _getThumbStart = (value: number) => {
            var ratio = this._getRatio(value);

            var start = 0;

            if (this.props.orientation === 'horizontal') {
              var length = this.state.containerSize.width - this.state.thumbSize.width;
              start = ratio * length;
            } else {
              var length = this.state.containerSize.height - this.state.thumbSize.height;
              start = length - (ratio * length);
            }

            return start;
          };

          _getValue = (gestureState: Object) => {
            var length = 0;

            if (this.props.orientation === 'horizontal') {
              length = this.state.containerSize.width - this.state.thumbSize.width;
            } else {
              length = this.state.containerSize.height - this.state.thumbSize.height;
            }

            var thumbStart = this._previousStart;

            var ratio;
            /*
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                THE NEXT STATEMENT IS EDITED TO AUTOMATICALLY TAKE ROTATED INPUTS FROM THE USER. EDIT IF "ORIENTATION" WORKS!

              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            */
            if (this.props.orientation === 'horizontal') {
              thumbStart += -gestureState.dy;
              ratio = (thumbStart / length);
            } else {
              thumbStart += gestureState.dy;
              ratio = 1 - (thumbStart / length);
            }

            if (this.props.step) {
              return Math.max(this.props.minimumValue,
                Math.min(this.props.maximumValue,
                  this.props.minimumValue + Math.round(ratio * (this.props.maximumValue - this.props.minimumValue) / this.props.step) * this.props.step
                )
              );
            } else {
              return Math.max(this.props.minimumValue,
                Math.min(this.props.maximumValue,
                  ratio * (this.props.maximumValue - this.props.minimumValue) + this.props.minimumValue
                )
              );
            }
          };

          _getCurrentValue = () => {
            return this.state.value.__getValue();
          };

          _setCurrentValue = (value: Number) => {
            this.state.value.setValue(value);
          };

          _setCurrentValueAnimated = (value: Number) => {
            var animationType   = this.props.animationType;
            var animationConfig = Object.assign(
                  {},
                  DEFAULT_ANIMATION_CONFIGS[animationType],
                  this.props.animationConfig,
                  {toValue : value}
                );
                // #######################################################################################################################
                // I CHANGED THIS THIS.STATE IN THE NEXT LINE SO THAT IT WOULD CHANGE THE HEIGHT OF MY IMAGES STYLE IN AN ANIMATION BUT IT DID NOT WORK
            Animated[animationType](this.state.imageBGStyle.height, animationConfig).start();
          };

          _fireChangeEvent = (event) => {
            if (this.props[event]) {
              this.props[event](this._getCurrentValue());
            }
          };

          _getTouchOverflowSize = () => {
            var state = this.state;
            var props = this.props;

            var size = {};
            if (state.allMeasured === true) {

              if (props.orientation === 'horizontal') {
                size.width = Math.max(0, props.thumbTouchSize.width - state.thumbSize.width);
                size.height = Math.max(0, props.thumbTouchSize.height - state.containerSize.height);
              } else {
                size.width = Math.max(0, props.thumbTouchSize.width - state.containerSize.width);
                size.height = Math.max(0, props.thumbTouchSize.height - state.thumbSize.height);
              }
            }

            return size;
          };

          _getTouchOverflowStyle = () => {
            var {width, height} = this._getTouchOverflowSize();

            var touchOverflowStyle = {};
            if (width !== undefined && height !== undefined) {
              var verticalMargin = -height / 2;
              touchOverflowStyle.marginTop = verticalMargin;
              touchOverflowStyle.marginBottom = verticalMargin;

              var horizontalMargin = -width / 2;
              touchOverflowStyle.marginLeft = horizontalMargin;
              touchOverflowStyle.marginRight = horizontalMargin;
            }

            if (this.props.debugTouchArea === true) {
              touchOverflowStyle.backgroundColor = 'orange';
              touchOverflowStyle.opacity = 0.5;
            }

            return touchOverflowStyle;
          };

          _thumbHitTest = (e: Object) => {
            var nativeEvent = e.nativeEvent;
            var thumbTouchRect = this._getThumbTouchRect();

            return thumbTouchRect.containsPoint(nativeEvent.locationX, nativeEvent.locationY);
          };

          _getThumbTouchRect = () => {
            var state = this.state;
            var props = this.props;
            var touchOverflowSize = this._getTouchOverflowSize();

            var rect = new Rect(
              0,
              0,
              props.thumbTouchSize.width,
              state.containerSize.height
            );

            if (this.props.orientation === 'horizontal') {
              rect.x = touchOverflowSize.width / 2 + this._getThumbStart(this._getCurrentValue()) + (state.thumbSize.width - props.thumbTouchSize.width) / 2;
              rect.y = touchOverflowSize.height / 2 + (state.containerSize.height - props.thumbTouchSize.height) / 2;
            } else {
              rect.x = touchOverflowSize.width / 2 + (state.containerSize.width - props.thumbTouchSize.width) / 2;
              rect.y = touchOverflowSize.height / 2 + this._getThumbStart(this._getCurrentValue()) + (state.thumbSize.height - props.thumbTouchSize.height) / 2;
            }

            return rect;
          };

          _renderDebugThumbTouchRect = (thumbStart) => {
            var thumbTouchRect = this._getThumbTouchRect();

            var positionStyle = {
              left: thumbTouchRect.x,
              top: thumbTouchRect.y,
              width: thumbTouchRect.width,
              height: thumbTouchRect.height,
              flex: 1,
              flexDirection: 'column',
              justifyContent: 'center'
            };

            if (this.props.orientation === 'horizontal') {
              positionStyle.left = thumbStart;
            } else {
              positionStyle.top = thumbStart;
            }
            return (
              <Animated.View
                style={[defaultStyles.debugThumbTouchArea, positionStyle]}
                pointerEvents='none'
              />
            );
          };

          _renderThumbImage = () => {
            var {thumbImage} = this.props;

            if (!thumbImage) return; 


            return {thumbImage};
          };
        };


        var defaultStyles = StyleSheet.create({
          container: {
            // height: 440,
            justifyContent: 'center',

          },
          track: {
            height: TRACK_SIZE,
            borderRadius: TRACK_SIZE / 2,

          },
          thumb: {
            position: 'absolute',
            width: THUMB_SIZE,
            height: '100%',
            borderRadius: THUMB_SIZE / 2,

          },
          thumbImgStyle: {
            resizeMode: 'contain',
            width: '100%',
            height: '100%',
            backgroundColor:'transparent'
          },
          thumbImgStyleBg: {
            resizeMode: 'contain',
            width: '100%',
            height: '100%',
            backgroundColor:'transparent'
          },
          trackImgStyle: {
            resizeMode: 'contain',
            flex: 1,
            width: '100%',
            height: '100%',
          },
          touchArea: {
            position: 'absolute',
            backgroundColor: 'transparent',
            top: '-40%',
            left: 0,
            right: 0,
            bottom: '-40%',
          },
          debugThumbTouchArea: {
            position: 'absolute',
            backgroundColor: 'green',
            opacity: 0.5,

          }
        });`

1 个答案:

答案 0 :(得分:0)

我找到了答案,

我最终使用了传入自定义动画的LayoutAnimation,但我遇到的问题与动画完全没有关系,而是它如何处理this.setState()。我刚刚使用了setState,然后使用了setTimeout()来确保在动画运行时更新了状态,因为我有动画从100%到100%并且它根本没有动画,因为它会将宽度设置为0%并且不将动画设置回100%,因为在动画期间它仍然是100%而不是0%。我足够新,能够做出反应,原因是没有理解为什么,但我的猜测是它与this.setState有关,后来运行的时间比我的动画代码要长,因而没有效果。

我确保在未来的问题中更加清晰,因为这太过模糊,无法提供帮助。