React-native/React 公告滚动组件(原生代码)

编写不易, 希望大家点赞

import React, {PureComponent} from 'react';
import {Animated, Easing, View} from 'react-native';

export default class NoticeScroll extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      newChildren: this.props.children,
    };
    this.animation = new Animated.Value(0);
    this.direction = this.props.direction === 'vertical' ? 'height' : 'width';
    this.transationValue = this.props.styles[this.direction];
    this.key = 0;
    this.arr = [];
  }

  startAnimation() {
    const meter = this.props.meter || 0;
    Animated.timing(this.animation, {
      toValue: -this.transationValue + meter,
      duration: this.props.scrolltime || 5000,
      easing: Easing.linear,
      useNativeDriver: true,
    }).start(() => {
      this.animation = new Animated.Value(0);
      this.initPosition();
      this.startAnimation();
    });
  }

  initPosition() {
    this.key++;
    if (this.key < 2) {
      // React.Children.forEach(this.props.children, (child, index) => {
      //     let props = {
      //         key: `${this.key}${index}`,
      //         ...child.props
      //     };
      //     this.arr.push(React.cloneElement(child, props));
      // });
      React.Children.forEach(this.props.children, (child, index) => {
        let newProps = {
          key: `${this.key}${index}flag`,
          ...child.props,
        };
        this.arr.push(React.cloneElement(child, newProps));
      });
    }

    this.setState({
      newChildren: [...this.arr],
    });
  }

  componentDidMount() {
    this.initPosition();
    this.startAnimation();
  }

  componentWillUnmount() {
    this.startAnimation = () => {};
  }

  render() {
    const {styles, direction} = this.props;
    const {newChildren} = this.state;
    return (
      <View style={{overflow: 'hidden', height: 35, justifyContent: 'center'}}>
        <Animated.View
          style={{
            transform: [
              direction !== 'vertical'
                ? {translateX: this.animation}
                : {translateY: this.animation},
            ],
            flexDirection: 'row',
          }}>
          {newChildren}
        </Animated.View>
      </View>
    );
  }
}

组件可以在React中直接使用,把Animated.View 改成Animated.div即可

 

此代码有一个不好的地方,就是只能读取本地的,否则会有延迟

 

 

优化代码!!!

import React, { Component } from 'react';
import { View, Animated, Easing, Text, TouchableOpacity, InteractionManager } from 'react-native';

const styles = {
    bgContainerStyle : {
        flexDirection : 'row',
        alignItems : 'center',
        justifyContent : 'flex-start',
        backgroundColor : '#FFFFFF',
        overflow : 'hidden'
    },
    textMeasuringViewStyle: {
        flexDirection : 'row',
        opacity : 0,
    },
    textMeasuringTextStyle: {
        fontSize : 16,
    },
    textStyle : {
        fontSize : 16,
        color : '#000000',
    }
};

export default class ScrollAnnounce extends Component {
    constructor(props) {
        super(props);
        this.state = {
            animation : null,
            textList : [],
            textWidth : 0,
            viewWidth : 0,
            start:false
        }
    }

    static defaultProps = {
        duration : 10000,
        speed : 0,
        textList : [],
        width : 375,
        height : 50,
        direction : 'left',
        reverse : false,
        separator : 20,
        onTextClick : () => {},
    }

    componentWillMount(){
        this.setState({
            textList : this.props.textList || [],
        })
        this.animatedTransformX = new Animated.Value(0);
    }

    componentDidUpdate(){
        let { textWidth, viewWidth } = this.state;
        let { duration, speed, width, direction } = this.props;
        let mDuration = duration;
        if(speed && speed > 0){
            mDuration = (width + textWidth) / speed * 1000;
        }
        if(!this.state.animation && textWidth && viewWidth){
            this.animatedTransformX.setValue(direction == 'left' ? width : (direction == 'right' ? -textWidth : width));
            this.setState({
                animation : Animated.timing(this.animatedTransformX, {
                    toValue: direction == 'left' ? -textWidth : (direction == 'right' ? width : -textWidth),
                    duration: mDuration,
                    useNativeDriver: true,
                    easing: Easing.linear,
                }),
            }, () => {
                this.state.animation && this.state.animation.start(() => {
                    this.setState({
                        animation: null,
                    });
                });
            })
        }

    }




    componentWillReceiveProps(nextProps){
        let newText = nextProps.textList || [];
        let oldText = this.props.textList || [];
        if (newText !== oldText) {
            this.state.animation && this.state.animation.stop();
            this.setState({
                textList : newText,
                animation: null,
                start:true
            });
        }
    }

    componentWillUnmount(){
        this.state.animation && this.state.animation.stop();
    }

    textOnLayout = (e) => {
        let width = e.nativeEvent.layout.width;
        let { textList, separator } = this.props;
        this.setState({
            textWidth : width + ((textList.length - 1) * separator),
        })
    }

    viewOnLayout = (e) => {
        let width = e.nativeEvent.layout.width;
        this.setState({
            viewWidth : width,
        })
    }

    textView(list){
        let { textStyle, onTextClick, reverse, separator } = this.props;
        let itemView = [];
        for(let i = 0;i<list.length;i++){
            let item = list[i];
            if(reverse){
                item.value = item.value.split("").reverse().join("");
            }
            itemView.push(
                <TouchableOpacity key = {''+i} activeOpacity = {0.9} onPress = {() => {
                    onTextClick(item)
                }}>
                    <View style = {{flexDirection : 'row',marginRight : i < list.length - 1 ? separator : 0}}>
                        <Text style = {{
                            ...styles.textStyle,
                            ...textStyle
                        }}
                              numberOfLines = {1}
                        >{item.value}</Text>
                    </View>
                </TouchableOpacity>
            );
        }
        return(
            <Animated.View
                style = {{flexDirection : 'row',width : this.state.textWidth,transform: [{ translateX: this.animatedTransformX }]}}
                onLayout={(event) => this.viewOnLayout(event)}
            >
                {itemView}
            </Animated.View>
        )

    }

    textLengthView(list){
        let { textStyle } = this.props;
        let text = '';
        for(let i = 0;i<list.length;i++){
            text += list[i].value;
        }
        return(
            <View style = {{
                ...styles.textMeasuringViewStyle,
                width : list.length * 1024
            }}>
                <Text style = {{
                    ...styles.textMeasuringTextStyle,
                    ...textStyle
                }}
                      onLayout={(event) => this.textOnLayout(event)}
                      numberOfLines = {1}
                >{text}</Text>
            </View>
        )

    }

    render(){
        let { width, height, bgContainerStyle } = this.props;
        let { textList,start } = this.state;
        return(
            <View style = {{
                ...styles.bgContainerStyle,
                width : width,
                height : height,
                ...bgContainerStyle,
            }} opacity = {this.state.animation ? 1 : 0}>
                {start&&this.textView(textList) }
                {start&&this.textLengthView(textList) }
            </View>
        )

    }
}
ScrollAnnounce
<ScrollAnnounce
    textList = {noticeList}
    speed = {60}
    width = {Platform.OS==='ios'?autoWidth(283):autoWidth(295)}
    height = {30}
    direction = {'left'}
    reverse = {false}
    bgContainerStyle = {{backgroundColor : '#f8f8f8'}}
    textStyle = {{fontSize : 12,color : '#D1B793'}}
    onTextClick = {(item) => {
        this._toDetail(item)
    }}
/>
posted @ 2019-12-16 14:49  一路向北√  阅读(1322)  评论(0编辑  收藏  举报

web应用开发&研究 -

业精于勤而荒于嬉。

工作,使我快乐。


Font Awesome | Respond.js | Bootstrap中文网