Flex播放器(实现播放、缓冲进度条和音频曲线显示)
Flex播放器(实现播放、缓冲进度条和音频曲线显示)
发布时间:2016-12-29 来源:查字典编辑
摘要:一时兴起,玩起了Flex,本来还想要做个Flex博客,不过目前还只能在里面树个公告。。。没办法做完啊,河蟹的个杯具的!Flex布局不像是CS...

一时兴起,玩起了Flex,本来还想要做个Flex博客,不过目前还只能在里面树个公告。。。没办法做完啊,河蟹的个杯具的!Flex布局不像是CSS,精美Flash动画不是拖一个两个控件就能做出来滴,而是一笔一条线绘制出来滴!这些我都还不熟悉,所有折腾快一个星期了,每天都是搞到头大才睡觉,今天终于能出一个简单的播放器。

一直很喜欢音乐这个东西,喜欢Jay,更喜欢他的歌,也很崇拜小猪,他的一段灰色空间曾让我激流奋进,想过自己能做个播客放自己喜欢听的歌曲,出于自恋那样会更有一点点满足感。呃~走神了,前二天无意看到一群教师的个人博客,深深的被他们的博文所吸引,无论是谈技术还是记录生活的,写得都是那么的真切,还有坚持每日一博的,坚持不放弃...

mx:ProgressBar实现加载歌曲缓冲进度条

ProgressBar有三大mode模式,分别为event、manual、polled,event为基于事件驱动模式,可设置source对象自动显示加载进程;manual为手动模式,需要调用ProgressBar.setProgress()方法设置滚动条进度;polled为轮询模式,本例使用的manual模式,Sound加载load请求歌曲添加一个ProgressEvent.PROGRESS处理中监听事件,然后根据Sound已加载的bytes和bytesTotal数,设置setProgress进度。这里需要注意在切换歌曲的时候先要移除ProgressEvent.PROGRESS事件,否则之前播放歌曲还未加载完又切换load新歌曲时回出现ProgressBar触发多个PROGRESS事件被设置进度出现来回滚动的问题。

mx:HSlide调节滑秆

这个控件在本例中2处使用,实现对播放进度和声音大小的控制。最一开始调整播放进度的问题难倒了我很久,因为在歌曲播放过程中HSlide要自动滑动当前播放位置,同时又需要能手动拖动播放位置,HSlide本来有一个很好的change事件用来侦听改变,但是我使用定时器设置HSlide的value的时竟然也给我触发change事件,参考了Adobe哥官网的帮助文档,说是Slider 组件的值因鼠标或键盘交互操作而改变时调度,如果 liveDragging 属性是 true,则在用户移动滑块时持续调度该事件。 如果 liveDragging 是 false,则在用户释放滑块时调度该事件。但是无论我怎么设置,在代码里改变了HSlide的value值怎会触发change事件,不是说在用户交互操作而改变时调度吗?无赖啊,后来只能折中采取监听thumbDrag滑秆拖动时事件,这个事件Adobe哥的解释是当按下滑块并随后随鼠标移动时调度,这样会有一个小问题,就是需要拖动滑秆按下时才会触发,点击无效。

SoundMixer.computeSpectrum()分析音频曲线

本例你看到显示的音频曲线其实是右64个绘制成条状的Canvas控件排列而成,然后使用定时器每间隔100毫秒重新设置他们的scaleY位置以呈现出变幻曲线的效果,代码只有三行很简单,具体可参见我下面源码给出的timerTick事件。这里为什么要用定时器呢?在网上看别人是监听Event.ENTER_FRAME事件重绘音频曲线的,不想搞那么麻烦就直接用定时器了,随便根据bytesTotal和bytesLoaded计算下歌曲播放时间,使用100毫秒的定时器也并好耗站资源,CPU没有涨很高。

效果图:

Flex播放器(实现播放、缓冲进度条和音频曲线显示)1

mxml代码如下:

复制代码 代码如下:

<"1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="0" scroll="false" backgroundAlpha="0"

horizontalScrollPolicy="off" verticalScrollPolicy="off" verticalAlign="middle" horizontalAlign="center"

initialize="init(event)" layout="vertical" fontSize="14" paddingLeft="0" paddingTop="0" paddingRight="0" paddingBottom="0" >

<mx:Script>

<![CDATA[

import mx.formatters.DateFormatter;

import mx.effects.SoundEffect;

import mx.events.SliderEvent;

import mx.core.SoundAsset;

import mx.controls.Alert;

import mx.managers.CursorManager;

import flash.media.*;

import flash.utils.Timer;

[Embed(source="images/cursor.gif")]

private var cursorHand : Class;//图标

private var xml:XML;

private var xmlPath:String = "/flex/bin-debug/song.xml";

private var currIndex : Number = 0;

private var song :Sound;

private var channel :SoundChannel;

private var position : Number = 0;

// 保存 512 个声音波形的快照

private var bytes:ByteArray = new ByteArray();

// SoundBar 的个数

private var barNum:uint = 64;

// 保存所有 SoundBar 的引用

private var soundBars:Array = new Array();

//定时器

private var timer : Timer;

//Application的initialize初试化事件

private function init(event:Event):void

{

var loader:URLLoader = new URLLoader();

loader.load(new URLRequest(xmlPath));

loader.addEventListener(Event.COMPLETE,Xml_Complete);

timer = new Timer(100);

timer.addEventListener(TimerEvent.TIMER,timerTick);

var barWidth:Number = boxSoundBar.width*1.00/barNum;

// 初始化Canvas为音频条,放入舞台并加入数组

for (var i:uint = 0; i < barNum; i++) {

var soundBar:Canvas = new Canvas();

soundBar.width = barWidth;

soundBar.height = boxSoundBar.height;

soundBar.x = i * barWidth;

soundBar.y = 0;

var g:Graphics = soundBar.graphics;

g.lineStyle(1,0x6688AA,1);

g.beginGradientFill(GradientType.RADIAL,[0x33cc00,0x456628],[1,1],[0,255],null,SpreadMethod.REFLECT,InterpolationMethod.RGB,0);

g.drawRect(0,0,soundBar.width,soundBar.height);

g.endFill();

boxSoundBar.addChild(soundBar);

soundBars.push(soundBar);

}

// 隐藏一些内建的鼠标右键菜单项

this.contextMenu.hideBuiltInItems();

var contextMenuItem : ContextMenuItem = new ContextMenuItem("Powered By: Jonllen");

contextMenuItem.enabled = false;

contextMenu.customItems.push(contextMenuItem);

this.contextMenu.customItems.push(contextMenuItem);

//更改鼠标图标

CursorManager.setCursor(cursorHand);

}

//读取XML文件完成事件

private function Xml_Complete(event:Event):void

{

xml = new XML(event.target.data);

if(xml.item.length()>=1)

{

listSong.dataProvider= xml.item.name;

listSong.selectedIndex = 0;

//手动触发List的Change事件

listSong.dispatchEvent(new mx.events.ListEvent(Event.CHANGE, true, false));

}

}

//List选择歌曲改变事件

private function Xml_Change(event:Event):void

{

currIndex = event.target.selectedIndex;

timer.stop();

//停止声音文件的加载

if( song!=null )

{

//移除之前加载PROGRESS事件对songProgress进度条的控制

song.removeEventListener(ProgressEvent.PROGRESS,songProgress_Change);

if( song.isBuffering )

song.close();

}

song = new Sound();

var url : String = xml.item[currIndex].url;

var source:URLRequest = new URLRequest(url);

song.load(source);

song.addEventListener(ProgressEvent.PROGRESS, songProgress_Change);

song.addEventListener(IOErrorEvent.IO_ERROR, songProgress_Error);

position = 0;

songStart();

}

//歌曲播放完成

private function songProgress_Complete(e:Event):void {

if(currIndex == xml.item.length()-1) {

currIndex = 0;

}else {

currIndex++;

}

listSong.selectedIndex = currIndex;

listSong.dispatchEvent(new mx.events.ListEvent(Event.CHANGE, true, false));

}

//加载歌曲失败

private function songProgress_Error(e:IOErrorEvent):void {

Alert.show("文件不存在!","系统提示");

}

//开始播放歌曲

private function songStart():void {

if ( channel != null ){

channel.stop();

}

lblName.text = xml.item[currIndex].name;

channel = song.play(position,int.MAX_VALUE);

var length :Number = song.length*song.bytesTotal/song.bytesLoaded;

var date : Date = new Date();

date.time = length;

var dt : DateFormatter = new DateFormatter();

dt.formatString="NN:SS";

var totalTime : String = dt.format(date);

date.time = channel.position;

lblTime.text = dt.format(date) + " | " + totalTime;

lblStatus.text = "播放";

var soundcontrol : SoundTransform = channel.soundTransform;

soundcontrol.volume = volumeSlider.value;

channel.soundTransform= soundcontrol;

timer.start();

boxSoundBar.visible = true;

}

//停止歌曲播放

private function songStop():void {

timer.stop();

position = 0;

boxSoundBar.visible = false;

lblTime.text = "00:00 |"+lblTime.text.split("|")[1];

lblStatus.text = "停止";

songSlider.value = songSlider.minimum;

songProgress.setProgress(songProgress.minimum,songProgress.maximum);

if ( channel != null )

{

channel.stop();

}

}

//暂停歌曲播放

private function songPause():void {

if ( channel != null ){

timer.stop();

position = channel.position;

channel.stop();

lblStatus.text = "暂停";

}

}

//加载歌曲进度条显示

private function songProgress_Change(e:ProgressEvent):void {

var percent:int = Math.round(e.bytesLoaded * 100 / e.bytesTotal);

songProgress.setProgress(e.bytesLoaded,e.bytesTotal);

}

//定时器方法

private function timerTick( e:TimerEvent):void {

if( channel!=null) {

var length :Number = song.length*song.bytesTotal/song.bytesLoaded;

var date : Date = new Date();

date.time = length;

var dt : DateFormatter = new DateFormatter();

dt.formatString="NN:SS";

var totalTime : String = dt.format(date);

date.time = channel.position;

lblTime.text = dt.format(date) + " | " + totalTime;

songSlider.value=100*channel.position/length;

if( songSlider.value>=songSlider.maximum){

timer.stop();

songProgress_Complete(null);

return;

}

SoundMixer.computeSpectrum(bytes, false, 0);

for (var i:uint = 0; i < barNum; i++) {

soundBars[i].scaleY = bytes.readFloat();

}

}

}

//歌曲进度调整事件

internal function songSlider_Change(e:SliderEvent):void{

timer.stop();

if ( channel != null ){

var length :Number = song.length*song.bytesTotal/song.bytesLoaded;

position = e.value*length/100;

songStart();

}

}

//声音大小调整事件

internal function changeVolume(evt:SliderEvent):void{

if ( channel != null ){

var soundcontrol : SoundTransform = channel.soundTransform;

soundcontrol.volume = evt.value;

channel.soundTransform= soundcontrol;

}

}

//设置歌曲播放时间和总时间

private function setTimeStatus():void {

var length :Number = song.length*song.bytesTotal/song.bytesLoaded;

var date : Date = new Date();

date.time = length;

var dt : DateFormatter = new DateFormatter();

dt.formatString="NN:SS";

var totalTime : String = dt.format(date);

date.time = channel.position;

lblTime.text = dt.format(date) + " | " + totalTime;

}

]]>

</mx:Script>

<mx:HBox width="100%" verticalGap="0" verticalAlign="middle" horizontalAlign="center">

<mx:Canvas width="440" borderColor="#CCCCCC" borderStyle="solid" height="171">

<mx:Label id="lblName" x="5" fontSize="18" y="10" text=""/>

<mx:HBox id="boxSoundBar" horizontalGap="0" verticalAlign="middle"

width="192" height="50" x="5" y="39" visible="false"></mx:HBox>

<mx:ProgressBar id="songProgress" label=""

width="290" height="3" mode="manual" textAlign="left"

labelPlacement="center" fontSize="3" x="10" y="97"

minimum="0" maximum="100" barColor="yellow"

trackColors="[white, haloSilver]"/>

<mx:HSlider id="songSlider" styleName="song" value="0"

showTrackHighlight="true" x="5" y="85" thumbDrag="songSlider_Change(event)"

width="300" height="22" minimum="0" maximum="100"

liveDragging="false" snapInterval="1" toolTip="拖动调整播放进度">

</mx:HSlider>

<mx:Label id="lblStatus" x="243" y="41" text=""/>

<mx:Label id="lblTime" x="205" y="66" text="00:00 | 5:23"/>

<mx:Button x="10" y="124" label="Play" click="songStart()"/>

<mx:Button x="74" y="124" label="Pause" click="songPause()"/>

<mx:Button x="152" y="124" label="Stop" click="songStop()"/>

<mx:HSlider id="volumeSlider" styleName="volume" change="changeVolume(event)"

showTrackHighlight="true" value="0.5" x="222" y="133"

width="81" minimum="0" maximum="10" liveDragging="true"

snapInterval="0.1" toolTip="音量调节" />

<mx:Label x="308" fontSize="18" y="10" text="歌曲列表"/>

<mx:List id="listSong" alpha="0.25" x="308" y="43" height="116"

change="Xml_Change(event)" width="130" toolTip="点击选择歌曲"></mx:List>

</mx:Canvas>

</mx:HBox>

</mx:Application>

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新Flex学习
热门Flex学习
编程开发子分类