小程序音頻播放圓形進度條

最近,因為業務需要,研究了一波圓形進度條的實現,最終采用了如下這種方式。


先上效果圖:


sound.gif

實現思路

  • 重點參照了 詳解用CSS3制作圓形滾動進度條動畫效果 的第三種效果。即采用兩個矩形截取完整的兩個圓,利用.progress_wrapperoverflow: hidden;屬性防止整圓溢出,表現為兩個半圓拼接為一個整圓。然后旋轉矩形里面的圓,通過改變旋轉角度逐漸顯示隱藏的圓形部分,表現為音頻進度條的變化。
  • 另外,這個圓形進度條有點小bug,在兩個半圓下方接口處會有一像素的空隙,我采用了一像素背景圖配合絕對定位填補這個空隙

WXML代碼

核心圓形進度條wxml代碼

<view class="circle_container">
  <view class="circle_wrapper">
    <view class="progress_wrapper circle_right">
      <view class="circle_progress right_circle" style="transform: rotate({{rightDeg}});"></view>
    </view>
    <view class="progress_wrapper circle_left">
      <view class="circle_progress left_circle" style="transform: rotate({{leftDeg}});"></view>
    </view>
    <image src="/images/{{play?'template_play03':'template_play'}}.png" class='play_audio' catchtap='pause_audio'></image>
    <view style="visibility: {{visible}}" class="circle_markup"></view>
  </view>
</view>

WXSS代碼

圓形進度條樣式

.circle_container {
  position: absolute;
  width: 56rpx;
  height: 56rpx;
  right: 30rpx;
  bottom: 20rpx;
}

.circle_wrapper {
  position: relative;
  width: 56rpx;
  height: 56rpx;
}

.progress_wrapper {
  width: 28rpx;
  height: 56rpx;
  position: absolute;
  top: 0;
  overflow: hidden;
}

.circle_right {
  right: 0;
}

.circle_left {
  left: 0;
}

.circle_progress {
  width: 48rpx;
  height: 48rpx;
  border: 4rpx solid #fff;
  border-radius: 50%;
  position: absolute;
  top: 0;
  transform: rotate(45deg);
}

.right_circle {
  border-top: 4rpx solid transparent;
  border-right: 4rpx solid transparent;
  right: 0;
}

.left_circle {
  border-bottom: 4rpx solid transparent;
  border-left: 4rpx solid transparent;
  left: 0;
}

.circle_markup {
  position: absolute;
  left: 28rpx;
  bottom: 0;
  width: 2rpx;
  height: 4rpx;
  background: #fff;
  visibility: hidden;
}

JS代碼

使用了WePY框架,其中,formatNumber格式化時間樣式,isPlay控制音頻播放圖標,isStop控制播放懸浮框是否顯示,time表示音頻當前播放時間,duration表示音頻總時長,percent表示音頻進度條,play控制懸浮框音頻播放圖標,title表示音頻標題,rightDeg表示右側半圓旋轉角度,leftDeg表示左側半圓旋轉角度,visible控制圓形進度條空隙是否顯示

import wepy from 'wepy'
  import {
    formatNumber
  } from '@/utils/util'
  export default class Index extends wepy.page {
    config = {
      navigationBarTitleText: '測試'
    }
    data = {
      isPlay: false,
      isStop: true,
      duration: '',
      percent: 0,
      play: true,
      title: '今日片尾',
      time: '',
      rightDeg: '',
      leftDeg: '',
      visible: 'hidden'
    }
    methods = {
      play_audio_func() {
        const audio = wx.getBackgroundAudioManager()
        audio.src = 'http://audio.heardtech.com/endAudio.mp3'
        audio.title = '今日片尾'
      }
    }
    onLoad() {
      let leftDeg = ''
      let rightDeg = ''
      let visible = ''
      let currentTime = 0
      let duration = 0
      const audio = wx.getBackgroundAudioManager()
      audio.onPlay(() => {
        this.isPlay = true
        this.isStop = false
      })
      audio.onPause(() => {
        this.isPlay = false
        this.isStop = false
      })
      audio.onStop(() => {
        this.isPlay = false
        this.isStop = true
      })
      audio.onEnded(() => {
        // audio.onTimeUpdate(() => {})
        this.percent = 0
        this.isPlay = false
        this.isStop = true
      })
      audio.onError((e) => {
        console.log('音頻播放錯誤', e)
      })
      audio.onTimeUpdate(() => {
        let audioData = this.computePercent(audio)
        this.percent = audioData.percent
        this.time = audioData.time
        currentTime = audioData.currentTime
        duration = audioData.duration
        this.duration = audioData.dtime
        // 右側半圓在進度超過一半之后要保持旋轉225deg狀態,未超過一半,左側半圓保持原始角度45deg
        if (currentTime / duration <= 0.5) {
          leftDeg = '45deg'
          rightDeg = currentTime / duration * 360 + 45 + 'deg'
          visible = 'hidden'
        } else {
          leftDeg = currentTime / duration * 360 + 225 + 'deg'
          rightDeg = '225deg'
          visible = 'visible'
        }

        this.rightDeg = rightDeg
        this.leftDeg = leftDeg
        this.visible = visible

        this.$apply()
      })
    }
    computePercent(audio) {
      let currentTime = parseInt(audio.currentTime)
      let duration = parseInt(audio.duration)
      let min = parseInt(currentTime / 60)
      let sec = parseInt(currentTime % 60)
      let dmin = parseInt(duration / 60)
      let dsec = parseInt(duration % 60)
      let time = formatNumber(min) + ':' + formatNumber(sec)
      let dtime = formatNumber(dmin) + ':' + formatNumber(dsec)
      let percent = parseInt(currentTime / duration * 100)
      console.log('currentTime:', currentTime, 'percent:', percent, 'duration:', duration)
      return {
        time,
        dtime,
        percent,
        currentTime,
        duration
      }
    }
  }
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網絡請求組件 FMDB本地數據庫組件 SD...
    陽明AGI閱讀 16,003評論 3 119
  • 古典專欄《22-2 寫給努力卻學不好的人,給大腦注入知識晶體》讀后反思 一、筆記 你知道鉆石之所以比同樣組成元素的...
    丹丹自語閱讀 670評論 0 0
  • “用雪把火埋了,我們該走了。” “恩。這是第幾天了?” “第八天,還有五天吧,還有十八天‘白夜’才會結束,你可要堅...
    銀色金屬閱讀 233評論 0 0
  • 晚飯過后,涼風習習,恰逢周末。踏上單車,塞上耳機,身披夕陽余暉,一路蹬到開遠市滇南發電總廠——是的,就是那個7路、...
    聆聽_自然閱讀 297評論 0 0