如何在react-native实现自定义的垂直方向跑马灯

容宏逸
2023-12-01

项目需求是需要实现一个垂直方向的跑马灯轮播,早期采用react-native-swiper解决方案,此方案在ios端正常使用,在android端不能使用,所有果断放弃。

第二方案打算使用ant-mobile的Carousel组件,

import { Carousel, WingBlank } from 'antd-mobile';
import { Text } from 'react-native';
 <Carousel 
     vertical
     dots={false}
     dragging={false}
     swiping={false}
     autoplay
     infinite
     style={{height:36}}
 >
   <Text style={{height:36}}>carousel 1</Text>
   <Text style={{height:36}}>carousel 2</Text>
   <Text style={{height:36}}>carousel 3</Text>
</Carousel>

出现了相当神奇的结果,竟然是横向滚动的,放弃。

尝试无果,又由于时间原因,自己封装,直接上代码:

import React, { Component } from 'react'
import {
  StyleSheet,
  View,
  Image,
  Text,
  Platform,
  TouchableOpacity,
  TouchableWithoutFeedback,
  Animated,
  Easing
} from 'react-native'

export default class MyNoticeBar extends Component {
  constructor(props) {
    super(props)
    this.state = {
      translateY: new Animated.Value(0)
    }
  }

  componentWillReceiveProps(props) {
    if(props.dataSource && props.dataSource.length != this.props.dataSource.length){
      this.showHeadBar(0, props.dataSource.length + 1)
    }
  }

  showHeadBar(index, count) {
    index++
    Animated.timing(this.state.translateY, {
      toValue: -30 * index, //40为文本View的高度
      duration: 300, //动画时间
      Easing: Easing.linear,
      delay: 1500 //文字停留时间
    }).start(() => {
      //每一个动画结束后的回调
      if (index >= count) {
        index = 0
        this.state.translateY.setValue(0)
      }
      this.showHeadBar(index, count) //循环动画
    })
  }

  render() {
    const {
      containerStyle,
      dataSource,
      onPress,
      iconStyle,
      iconSrc,
      textStyle
    } = this.props

    let tmpArr = dataSource.length ? [...dataSource, dataSource[0]] : null
    //如果不添加数据第一条的话会出现最后一条空白滚动

    return (
      <TouchableWithoutFeedback
        onPress={
          onPress
            ? onPress
            : () => {
                console.log('pressed')
              }
        }
      >
        <View style={[styles.container, containerStyle ? containerStyle : '']}>
          <Image
            style={[iconStyle ? iconStyle : '', styles.icon]}
            source={
              iconSrc ? iconSrc : require('./../assets/1.3/news_white.png')
            }
          />
          <Animated.View
            style={[
              styles.swiper,
              {
                transform: [
                  {
                    translateY: this.state.translateY
                  }
                ]
              }
            ]}
          >
            {tmpArr &&
              tmpArr.map((item, index) => {
                return (
                  <View
                    style={[
                      styles.viewForText
                    ]}
                    key={index}
                  >
                    <Text style={[styles.text,textStyle?textStyle:'']}>{item.content}</Text>
                  </View>
                )
              })}
          </Animated.View>
        </View>
      </TouchableWithoutFeedback>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: 'rgba(0,0,0,0.06)',
    borderRadius: 4,
    paddingLeft: 15,
    flexDirection: 'row',
    alignItems: 'flex-start',
    position: 'relative',
    width: 306,
    height: 30,
    overflow: 'hidden'
  },
  swiper: {
  },
  icon: {
    width: 15,
    height: 15,
    position: 'relative',
    top: 7,
    zIndex: 5,
    marginRight: 8
  },
  viewForText: {
    alignItems: 'flex-start',
    justifyContent: 'flex-start',
  },
  text: {
    fontFamily: 'PingFangSC-Regular',
    fontSize: 12,
    color: '#FFF',
    lineHeight: 30,
  }
})

此解决方案效果是出来了,但是还是会出现最后一条记录和第一条记录之间的闪屏效果,暂未发现解决方案,如果有解决方案的话,欢迎留言分享。

 类似资料: