React-Native使用react-native-community/art实现水波纹、音频波动效果

 效果如下,可以通过改变volume值实现动态效果

效果展示

 

贴组件代码,复制就能用:

【依赖package.json】 

"@react-native-community/art": "^1.1.2",
"react-native": "0.61.4",

【组件代码DancingLine.tsx】 

import React, { PureComponent, } from 'react';

import {
  StyleSheet,
  View,
  Dimensions,
} from 'react-native';
import style from '../../constants/style';
import { Surface, Shape, Path } from '@react-native-community/art'
import _ from 'lodash';
import { observer } from 'mobx-react';
import { observable } from 'mobx';
const ScreenWidth = Dimensions.get('window').width;

const styles = StyleSheet.create({

})


interface IProps {
  volume: number,
  numberOfWaves?: number,
  waveColor?: string,
  waveWidth: number,
  waveHeight: number,
}


@observer
class DancingLine extends PureComponent<IProps> {

  // 传入波动值[0, 0.5]
  private volume: any = 0
  // 条数
  private numberOfWaves = 5
  // 颜色
  private waveColor: any = '#ff0000'
  // 主波线宽
  private mainWaveWidth: any = 2.0
  // 辅波线宽
  private decorativeWavesWidth: any = 1.0
  // 闲置时即最小振幅
  private idleAmplitude: any = 0.02

  private frequency: any = 1.2
  private density: any = 1.0

  private phaseShift: any = -0.25

  private phase: any = 0

  private amplitude: any = 1.0

  private waveHeight: any = 200
  private waveWidth: any = ScreenWidth
  private waveMid: any = this.waveWidth / 2.0
  private maxAmplitude: any = this.waveHeight - 4.0

  @observable
  private paths: any = []

  constructor(props: IProps) {
    super(props)
    const { numberOfWaves, waveColor, waveWidth, waveHeight } = this.props
    numberOfWaves && (this.numberOfWaves = numberOfWaves)
    waveColor && (this.waveColor = waveColor)
    waveWidth && (this.waveWidth = waveWidth)
    waveHeight && (this.waveHeight = waveHeight)
  }


  _updateVolume = () => {
    this.volume = this.props.volume
    this.phase += this.phaseShift;
    this.amplitude = Math.max(this.volume, this.idleAmplitude);

    // 绘制线条
    var paths = []
    for (let i = 0; i < this.numberOfWaves; i++) {

      let progress = 1.0 - i / this.numberOfWaves
      let normedAmplitude = (1.5 * progress - 0.5) * this.amplitude

      var speedStr = ''
      for (let x = 0; x < this.waveWidth + this.density; x += this.density) {
        // 使顶峰保持在视图中央
        let scaling = - Math.pow(x / this.waveMid - 1, 2) + 1
        let y = scaling * this.maxAmplitude * normedAmplitude * Math.sin(2 * Math.PI * (x / this.waveWidth) * this.frequency + this.phase) + (this.waveHeight * 0.5)

        if (x == 0) {
          speedStr += `M${x} ${y}`
        } else {
          speedStr += `L${x} ${y}`
        }
      }
      const path = new Path(speedStr);
      paths.push(path)
    }
    this.paths = paths
  }

  componentDidMount = () => {
    this._updateVolume()
  }

  shouldComponentUpdate(nextProps: IProps): boolean {
    if (this.props.volume == nextProps.volume) {
      return false
    }
    this._updateVolume()
    return true
  }

  render() {
    return <View style={{ width: this.waveWidth, height: this.waveHeight }}>
      {_.map(this.paths, (path, index: number) => {
        let strokeColor = ''
        if (index == 0) {
          strokeColor = this.waveColor
        } else {
          // 渐变浅色
          let progress = 1.0 - index / this.numberOfWaves
          let multiplier = Math.min(1.0, (progress / 3.0 * 2.0) + (1.0 / 3.0))
          if (multiplier == 0) {
            multiplier = 1
          }
          let num = parseInt(255 * multiplier + '')
          strokeColor = this.waveColor + num.toString(16)
        }

        let strokeWidth = index == 0 ? this.mainWaveWidth : this.decorativeWavesWidth;

        return <View style={{ height: this.waveHeight, width: this.waveWidth, position: 'absolute', }}>
          <Surface height={this.waveHeight} width={this.waveWidth}>
            <Shape d={path} stroke={strokeColor} strokeWidth={strokeWidth} />
          </Surface>
        </View>
      })
      }
    </View >
  }
}

export default DancingLine

【使用】

import DancingLine from "../../../components/view/DancingLine";
@observable
volume: number = 0
componentDidMount(): void {
   setInterval(() => {
       this.volume = Math.random() * 0.5
   }, 100)
}
<DancingLine volume={this.volume} waveWidth={Dimensions.get('window').width} waveHeight={300}/>

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值