Flex4中增加了一个视频播放组件:VideoPlayer,相信很多朋友已经在使用了,确实比原先方便很多(记得在Flex3的时候,我们还需要借用Flash IDE带的视频播放组件)。它的功能确实也足以覆盖我们大部分的一般性的需求。如果您有一些自定义的需求,比如需要自定义播放器的全屏行为,就要了解VideoPlayer的一些内部逻辑。
首先,VideoPlayer是支持全屏播放的,注意播放器的右下角有一个控制全屏状态的按钮,点击之后,视频就进入全屏状态,而播放条会位于稍微靠底部的位置,并且过一段时间后就会自动隐藏。再次点击全屏按钮,或按ESC键,即可退出全屏状态,恢复之前的默认状态。这是默认情况下,VideoPlayer的全屏行为。
如果我们为播放器实现了一个字幕显示功能,那么进入全屏状态后,如何把字幕也显示出来呢?来看一下具体的代码实现:
首先,要实现字幕功能,我们必然要对VideoPlayer的功能进行扩展。基于优先使用组合,而不是继承的建议,我们没有直接继承VideoPlayer,而是使用了Group,内部包含一个VideoPlayer和一个Text组件,Text组件显然是用来显示字幕的,它会叠加在VideoPlayer之上。
假设我们已经完成了字幕的解析和显示功能,那么在正常情况下,字幕播放是正常的,但是一旦进入全屏状态,我们就会发现字幕没有显示出来。因为显然用于显示字幕的Text组件在VideoPlayer之外。所以我们还需要做一些额外的工作,来把字幕显示也加入到VideoPlayer的全屏显示界面里面。
因为VideoPlayer也是基于皮肤机制的,所以我们需要为它指定一个自定义的皮肤(注意控制全屏的按钮,是在皮肤里面存在的),然后我们就可以控制全屏按钮的行为,禁用它的默认行为,并派发一个事件给我们的组件,这样我们的组件就可以在接受到事件之后,完成我们自定义的全屏代码的控制工作。代码里面我们直接注视掉了原先的按钮,增加一个显示和原先一致的新按钮,注意ID是不同的。
-
<!--
-
<s:Button id= "fullScreenButton" right= "0" bottom= "0" label= "Fullscreen"
-
skinClass= "spark.skins.spark.mediaClasses.normal.FullScreenButtonSkin"
-
skinClass.fullScreenStates= "spark.skins.spark.mediaClasses.fullScreen.FullScreenButtonSkin"
-
focusIn= "event.target.depth=1" focusOut= "event.target.depth=0"/>
-
-->
-
<s:Button id= "fullScreenButtonImp1" right= "0" bottom= "0" label= "Fullscreen"
-
skinClass= "spark.skins.spark.mediaClasses.normal.FullScreenButtonSkin"
-
skinClass.fullScreenStates= "spark.skins.spark.mediaClasses.fullScreen.FullScreenButtonSkin"
-
focusIn= "event.target.depth=1" focusOut= "event.target.depth=0" click= "dispatchEvent(new Event('videoFullScreen',true))"/>
注意它派发了一个"videoFullScreen"的事件,并且是冒泡的,所以会被我们的组件接收到。然后我们就可以自定义播放器的全屏行为了。参见下面的代码片段,这段代码参阅了VideoPlayer自身的代码,并针对需求进行了一些改动。注意它的全屏控制,并不是简单的设置stage.displayState,还需要用PopUpManager将组件自身添加到最顶层显示,并将尺寸放大到全屏尺寸(之所以要这样实施,是因为如果用stage.fullScreenSourceRect属性,简单的定义全屏显示区域的话,播放器本身的UI会在放大后出现明显的锯齿,显示非常丑陋)。代码我大体上进行了注释,如下:
-
private var beforeFullScreenInfo:Object ;
-
/**
-
* 全屏按钮被点击后,执行的事件侦听方法
-
*/
-
protected function fullScreenButtonHandler ( event:Event ): void
-
{
-
//判断状态,如果是全屏,就退出全屏,否则进入全屏
-
if (stage.displayState == StageDisplayState.FULL_SCREEN ) {
-
//注意这个设置会触发fullScreenEventHandler,返回初始状态,将组件归位
-
stage.displayState = StageDisplayState.NORMAL ;
-
} else {
-
var screenBounds:Rectangle = new Rectangle ( 0, 0,stage.fullScreenWidth,stage.fullScreenHeight ) ;
-
//这里要记录下当前组件的一些数据,用于返回初始状态的时候,将组件设置到原先的状态
-
beforeFullScreenInfo = {parent: this.parent,
-
x: this.x,
-
y: this.y,
-
explicitWidth: this.explicitWidth,
-
explicitHeight: this.explicitHeight,
-
percentWidth: this.percentWidth,
-
percentHeight: this.percentHeight,
-
isPopUp: this.isPopUp} ;
-
//获取组件在原先的父级上的索引
-
if (parent is IVisualElementContainer ){
-
var ivec:IVisualElementContainer = IVisualElementContainer (parent ) ;
-
beforeFullScreenInfo.childIndex = ivec.getElementIndex ( this ) ;
-
ivec.removeElement ( this ) ;
-
} else{
-
beforeFullScreenInfo.childIndex = parent.getChildIndex ( this ) ;
-
parent.removeChild ( this ) ;
-
}
-
//用PopUp机制,将组件添加到最上层显示
-
PopUpManager.addPopUp ( this, FlexGlobals.topLevelApplication as DisplayObject, false, null, moduleFactory ) ;
-
//设置组件的尺寸,匹配全屏下屏幕的尺寸
-
setLayoutBoundsSize (screenBounds.width, screenBounds.height, true ) ;
-
this.explicitWidth = width ;
-
this.explicitHeight = height ;
-
setLayoutBoundsPosition ( 0, 0, true ) ;
-
this.validateNow ( ) ;
-
systemManager.stage.addEventListener (FullScreenEvent.FULL_SCREEN, fullScreenEventHandler ) ;
-
stage.displayState = StageDisplayState.FULL_SCREEN ;
-
currentState = "fullScreen" ;
-
}
-
}
-
/**
-
* 屏幕状态切换的时候,触发的事件侦听方法
-
*/
-
private function fullScreenEventHandler ( event:FullScreenEvent ): void
-
{
-
//只判断状态从全屏进入普通模式的情况
-
if ( event.fullScreen ) return ;
-
currentState = "" ;
-
systemManager.stage.removeEventListener (FullScreenEvent.FULL_SCREEN, fullScreenEventHandler ) ;
-
//根据之前记录的数据,将组件归位
-
this.x = beforeFullScreenInfo.x ;
-
this.y = beforeFullScreenInfo.y ;
-
this.explicitWidth = beforeFullScreenInfo.explicitWidth ;
-
this.explicitHeight = beforeFullScreenInfo.explicitHeight ;
-
this.percentWidth = beforeFullScreenInfo.percentWidth ;
-
this.percentHeight = beforeFullScreenInfo.percentHeight ;
-
if (!beforeFullScreenInfo.isPopUp ){
-
// remove from top level application:
-
PopUpManager.removePopUp ( this ) ;
-
// add back to original parent
-
if (beforeFullScreenInfo.parent is IVisualElementContainer )
-
beforeFullScreenInfo.parent.addElementAt ( this, beforeFullScreenInfo.childIndex ) ;
-
else
-
beforeFullScreenInfo.parent.addChildAt ( this, beforeFullScreenInfo.childIndex ) ;
-
}
-
beforeFullScreenInfo = null ;
-
invalidateSize ( ) ;
-
invalidateDisplayList ( ) ;
-
}
转载:http://www.riameeting.com/node/1059