2007年2月26日星期一

带有喇叭的VideoDisplay的VolumeControl



关于FLV播放器VideoDisplay的自作,其实很多它外国友人已经把它做得屈近于完美,出于空闲加上一下自己个人的想法,自己就做了一个关于声音并自带喇叭的控制,我称它为VolumeControl.
喇叭的波形是由右边的值来控制的,你可以通过按喇叭来控制是否要静音,而且提供了3个颜色的接口(不填也有默认色),可以对喇叭,波,背景进行颜色的变化,当然,因为静音的符号一般都是红的,所以我没有对它提供颜色的变化接口,如果你要改变,当然改一下代码就可以了拉.
下面一段是喇叭控制的部分代码和VolumeControl的源代码.

PS:希望用到的朋友们能注明一下出处.


喇叭控制的部分代码:
private function setControlStatus():void{
FlexFLVVideoPlayer.volume = volumeControl.volume;
trace('mute'+FlexFLVVideoPlayer.volume);
}
< id="volumeControl" change="setControlStatus()" volume="0.3" loudspeakercolor="#000000" loudspeakerwavecolor="#ff0000" backgroundcolor="#00f000">


VolumeControl的源代码:
// ActionScript file--Edited By Aedis.Ju
package FlexFLV
{
import mx.core.UIComponent;
import mx.events.FlexEvent;
import flash.events.Event;
import mx.controls.Button;
import mx.controls.HSlider;
import mx.containers.HBox;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;
import flash.events.MouseEvent;
import mx.events.SliderEvent;
import flash.display.Graphics;

[Event(name="change", type="mx.events.SliderEvent")]

[Style(name="loudSpeakerColor", type="uint", format="Color", inherit="yes")]
[Style(name="loudSpeakerWaveColor", type="uint", format="Color", inherit="yes")]
[Style(name="backGroundColor", type="uint", format="Color", inherit="yes")]

public class VolumeControl extends UIComponent
{
[Embed(source="../Img/thumbDownSkin.gif")]
private var thumbDownSkin:Class;
[Embed(source="../Img/thumbOverSkin.gif")]
private var thumbOverSkin:Class;
[Embed(source="../Img/thumbUpSkin.gif")]
private var thumbUpSkin:Class;

private var _loudSpeaker:Button;
private var _loudControl:HSlider;
private var _backGround:HBox;
public function VolumeControl(){
super();
addEventListener(FlexEvent.CREATION_COMPLETE, drawBackGround);
}

//set defalut Style
private static var stylesInited:Boolean = initStyles();
private static var defalutStyle:CSSStyleDeclaration = new CSSStyleDeclaration();
private static function initStyles():Boolean {
defalutStyle = new CSSStyleDeclaration();
defalutStyle.setStyle("backgroundColor",0x000000);
defalutStyle.setStyle("loudSpeakerWaveColor",0x00ff00);
defalutStyle.setStyle("loudSpeakerColor",0xffffff);
StyleManager.setStyleDeclaration("VolumeControl", defalutStyle, true);
return true;
}
private function drawBackGround(e:FlexEvent):void {
//drawBackGround!
var backgroundColorUint:uint = getStyle('backGroundColor');
_backGround.setStyle('backgroundColor',backgroundColorUint);
}

private var _volume:Number;
public function get volume():Number {
if(_loudSpeaker.selected) return 0;
return _loudControl.value;
}
public function set volume(value:Number):void {
if(value < _volume =" 0;"> 1) {
_volume = 1;
} else {
_volume = value;
}
}

//if mute is true,thate means it is mute.
private var _mute:Boolean;
public function get mute():Boolean {
if(_loudSpeaker) return _loudSpeaker.selected;
return _mute;
}

override protected function createChildren():void{
super.createChildren()
if(!_backGround) {
_backGround = new HBox();
addChild(_backGround);
_backGround.setStyle('horizontalGap', 0);
}
if(!_loudSpeaker && _backGround) {
_loudSpeaker = new Button();
_loudSpeaker.toggle = true;
_loudSpeaker.useHandCursor = true;

_backGround.addChild(_loudSpeaker);

_loudSpeaker.addEventListener(MouseEvent.CLICK, drawloudSpeaker);

_loudSpeaker.setStyle("overSkin", null);
_loudSpeaker.setStyle("upSkin", null);
_loudSpeaker.setStyle("downSkin", null);

_loudSpeaker.setStyle("selectedUpSkin", null);
_loudSpeaker.setStyle("selectedOverSkin", null);
_loudSpeaker.setStyle("selectedDownSkin", null);
_loudSpeaker.setStyle("selectedDisabledSkin", null);
}
if(!_loudControl && _backGround) {

_loudControl = new HSlider();
_loudControl.snapInterval = 0.1;
_loudControl.maximum = 1;
_loudControl.value = _volume;

_backGround.addChild(_loudControl);

_loudControl.liveDragging = true;
_loudControl.addEventListener(SliderEvent.CHANGE, drawloudSpeaker);
_loudControl.addEventListener(FlexEvent.CREATION_COMPLETE, drawloudSpeaker);

_loudControl.setStyle("thumbDownSkin",thumbDownSkin);
_loudControl.setStyle("thumbOverSkin",thumbOverSkin);
_loudControl.setStyle("thumbUpSkin",thumbUpSkin);
}
}

private function drawloudSpeaker(e:Event):void {
//do change event!
var eventObj:SliderEvent = new SliderEvent("change");
dispatchEvent(eventObj);

//draw!
var loudSpeakerColorUint:uint = getStyle('loudSpeakerColor');
var graphics:Graphics = _loudSpeaker.graphics;
graphics.clear();
graphics.beginFill(loudSpeakerColorUint, 1);
graphics.moveTo(6,2);
graphics.lineTo(4,6);
graphics.lineTo(2,6);
graphics.lineTo(2,14);
graphics.lineTo(4,14);
graphics.lineTo(6,18);
graphics.moveTo(6,2);
graphics.curveTo(10,10,6,18);
graphics.endFill();

if(!_loudSpeaker.selected) {
_volume = _loudControl.value;
if(_loudControl.value <= 0) return; var loudSpeakerWaveUint:uint = getStyle('loudSpeakerWaveColor'); graphics.lineStyle(1.2, loudSpeakerWaveUint, 1); if(_loudControl.value > 0) {
graphics.moveTo(10, 2);
graphics.curveTo(14, 10, 10, 18);
}
if(_loudControl.value >= 1/2*_loudControl.maximum) {
graphics.moveTo(14, 4);
graphics.curveTo(18, 10, 14, 16);
}
if(_loudControl.value == _loudControl.maximum) {
graphics.moveTo(18, 6);
graphics.curveTo(20, 10, 18, 14);
}
} else {
_volume = 0;
graphics.lineStyle(2,0xff0000,1);
graphics.drawCircle(14.5, 10, 4.5);
graphics.moveTo((14.5 + 4.5*Math.sin(45)), (10 - 4.5*Math.sin(45)));
graphics.lineTo((14.5 - 4.5*Math.sin(45)), (10 + 4.5*Math.sin(45)));
}

}

override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
if(_loudSpeaker) {
_loudSpeaker.width = 20;
_loudSpeaker.height = 20;
_loudSpeaker.x = 0;
_loudSpeaker.y = 0;
}
if(_loudControl) {
_loudControl.width = 80;
_loudControl.height = 10;
_loudControl.x = _loudSpeaker.width;
_loudControl.y = 3;
}
if(_backGround) {
_backGround.width = _loudSpeaker.width+_loudControl.width;
_backGround.height = Math.max(_loudSpeaker.height, _loudControl.height);
_backGround.x = 0;
_backGround.y = 0;
}
super.updateDisplayList(unscaledWidth, unscaledHeight);
}

}
}

2007年2月13日星期二

Flex Style Explorer update to Version 2.0.1




今天是情人节,首先祝大家情人节快乐!

今天又跑到
Flex Style Explorer偷懒着去找好看的CSS式样对我的FlexFLVPlayer进行装饰,没想到发现Flex Style Explorer新年新气象,它已经跟随着Flex升级到了Version2.0.1,想想我们公司还在继续用着Flex2.0,对自己说,过年回来一定要对Flex2.0.1进行近一步的分析为大家升级到2.0.1的方便使用而努力!
这次主要改变不仅对
Flex Style Explorer的布局进行了更改,而且全新使用了Flex2.0.1的控件,使支持达到了新的高度,而且界面也美观了,只不过SANDBOX小了点,要通过最左边的ViewStack的缩放大小来改变它的大小,总的满意度还是可以的,而且非常喜欢.
意外的惊喜的是,这次它提供了
源代码显示,简直是对新手莫大的福音,你可以通过里面可以学到很多新的东西,比如,每一棵树它是怎么显示出自己的ICON的,为什么List旁边能显示一个打勾的小图标,它是怎么把你做好的CSS自动粘贴到的你的ClipBoard里面的 ...有经验的人马上也能看出Flex2.0.1跟Flex2.0对CSS的支持又有哪些重大的改变.

我想这是Adobe在情人节送我最好的礼物.
Adobe, Thank you!


Application

ViewSource

2007年2月7日星期三

HitTestPoint处理透明png和透明swf

上次已经介绍过一次Doug McCune ,如果你正在处理图片等问题方面的话,也许他真得是一个很不错的专家级人物.

这次他又一次给我们解决了一个我们认为的BUG:
我们一般用DisplayObject.hitTestPoint(x, y, obj):Boolean来判断x,y的位置是否存在在这个display object上,如果在上面的话,返回来是true.当object是透明的话,我们认为,这个方法返回的应该是false,就是说不在display object上面.
这次提到的是png图片和swf中透明的问题.大家经过验证得出来的结论就是:只要是png图片,flex认为它整个是一个实体,包括透明和不透明的,所以它一直返回的是true,但swf就不一样了,只要swf透明的地方,它返回的是false,不透明的地方返回的是true.

结论得出来了,问题是我们都一直认为透明不是'东西' ,既然不是'东西'返回的就应该是false.那怎么样让透明png图片的透明部分返回的是false呢?就象swf一样?
第一种:重新判断x,y下面的透明度,如果是0,返回的是false;
第二种:采用Doug的方法:写了一个realHitTest(obj,point).首先判断是不是BitmapData,如果是的话直接采用BitmapData自带的hitTest(firstPoint, firstAlphaThreshold, secondObject, secondBitmapDataPoint, secondAlphaThreshold):Boolean,当然,png和swf它们都不是BitmapData. 当png图片和swf不透明的时候,hitTestPoint(x, y, obj)返回来是true,这时候,就要进行处理了,让png透明的地方返回来是false,他把将要检测的display obje 转成一个BitmapData,然后用BitmapData的HitTest来进行检测.

代码片段:

if(object is BitmapData)
{
return (object as BitmapData).hitTest(new Point(0,0), 0, object.globalToLocal(point));
} else {
/* First we chack if the hitTestPoint method returns false. If it does, that * means that we definitely do not have a hit, so we return false. But if this * returns true, we still don't know 100% that we have a hit because it might * be a transparent part of the image. */
if(!object.hitTestPoint(point.x, point.y, true)) {
return false;
} else {
/* So now we make a new BitmapData object and draw the pixels of our object * in there. Then we use the hitTest method of that BitmapData object to * really find out of we have a hit or not. */
var bmapData:BitmapData = new BitmapData(object.width, object.height, true, 0x00000000);
bmapData.draw(object, new Matrix());
var returnVal:Boolean = bmapData.hitTest(new Point(0,0), 0, object.globalToLocal(point));
bmapData.dispose(); return returnVal;
}
}


Demo
View the source

Link:Using hitTestPoint or hitTest on Transparent PNG images by Doug McCune

knowledge:
DisplayObject --> EventDispatcher --> Object
hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false):Boolean
Evaluates the display object to see if it overlaps or intersects with the point specified by the x and y parameters.

BitmapData --> Object

hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean
Performs pixel-level hit detection between one bitmap image and a point, rectangle, or other bitmap image.

凹凸效果Button的实现

今天客户需要一个凹凸效果Button,没想到我还在想着怎么用皮肤来实现凹下去,旁边的同事就已经告诉我只要toggle="true",效果就能实现,按一下凹,按一下凸.然后我继续往下看源码才发现原来凹不凹凸不凸是由Button的selected是否等于true实现的.真不惊感叹一句:原来是这样!
下面写了2种相同的效果:
<mx:Button id="toggleBtnByToggle" label="toggleControl" toggle="true"/>
<mx:Button id="toggleBtnBySelected" label="selectedControl" click="changeSkin()"/>
<mx:Script>
<![CDATA[
private function changeSkin():void {
toggleBtnBySelected.selected = toggleBtnBySelected.selected ? false : true;
}
]]>
</mx:Script>

2007年2月6日星期二

FileReference中的过滤器

private var smallBrowser:FileReference = new FileReference();
private function openBrowser():void{
var fileTypes:FileFilter = new FileFilter("FLV文件 (*.flv)","*.flv");
var allTypes:Array = new Array(fileTypes);
smallBrowser.browse(allTypes);
smallBrowser.addEventListener(Event.SELECT, handleOpenBrowser);
}
private function handleOpenBrowser(event:Event):void{
trace("Selected!"+smallBrowser.name);
}

2007年2月5日星期一

Sprites和Shapes的区别之一

为什么Button的mouseChildren是false呢?


mouseChildren顾名思义,就是这个存在在object的
孩子是否应该响应到mouse events事件
我们知道Button的组成包括了UITextField,另外包括了很多的skins和icons.

skins包括了upSkinName,overSkinName,downSkinName,disabledSkinName,selectedUpSkinName,selectedOverSkinName,selectedDownSkinName,selectedDisabledSkinName;
icons则包括了iconName,upIconName,overIconName,downIconName,disabledIconName,selectedUpIconName,selectedOverIconName,selectedDownIconName,selectedDisabledIconName.
skins和icons这些用户其实都是可以重新自定义的.

最主要的目的是为了保证mouse events是从Button它自己本身的触发,而不是它的skins,icons,UITextField.

我们在定义skins和icons的时候,会用到Sprites和Shapes,如果mouseChildren是true的话,用到Sprites的会无法响应click事件,Shapes还会是正常的.为什么呢?这是因为用到Sprites,做click事件的时候,它将直接响应到skins或者icons,而不是Button它本身,而Shapes是不会响应mouse events的.为了不让有这种情况发生,mouseChildren = false.

knowledge:

mouseChildren : BooleanDetermines whether or not the children of the object are mouse enabled.

Shape ---> DisplayObject --->EventDispatcher ---> Object
The Shape class is used to create lightweight shapes by using the ActionScript drawing application program interface (API). The Shape class includes a graphics property, which lets you access methods from the Graphics class. The Sprite class also includes a graphicsproperty, and it includes other features not available to the Shape class. For example, a Sprite object is a display object container, whereas a Shape object is not (and cannot contain child display objects). For this reason, Shape objects consume less memory than Sprite objects that contain the same graphics.

Sprite --->DisplayObjectContainer--->InteractiveObject ---> DisplayObject ---> EventDispatcher ---> Object
The Sprite class is a basic display list building block: a display list node that can display graphics and can also contain children. A Sprite object is similar to a movie clip, but does not have a timeline. Sprite is an appropriate base class for objects that do not require timelines. For example, Sprite would be a logical base class for user interface (UI) components that typically do not use the timeline.The Sprite class is new in ActionScript 3.0. It provides an alternative to the functionality of the MovieClip class, which retains all the functionality of previous ActionScript releases to provide backward compatibility.

2007年2月4日星期日

歡迎加入RIADEV

现在是北京时间2月5号的凌晨1:20分,我还在看这MANUTD的比赛,一不小心Vidic和Scholes就连续短短几分钟进了2球,比分已经锁定在3:0,继续拉开这与切尔西的差距,心里面真是无比的开心啊。
闲着无比开心的心情,去逛了一下国人FLEX第一人Jeremy的BLOG,一看,有发现了一件喜事,我们的RIADEV终于再一次宣传出来了,为什么是宣传呐?因为其实这东西在去年就已经成立了,废话不多说了,我们就看看Jeremy给我们说的话吧。



中文 Flex, Apollo 討論群組 - 歡迎加入
RIADEV(http://groups.google.com/group/riadev)
是去年中成立的一個華文討論群組,當時本想仿效 flexcoders 在 yahoo groups 上建立,但可惜那個平台不支援中文,所以改到 google 設立。
這個群組成立的目地是希望提供一個使用中文討論 Flex, Apollo 的環境,這樣可讓不諳英文無法接觸 flexcoders 的華人開發者也有一個發問與尋求支援的管道。
使用 RIADEV 這個名稱主要是考量它的討論內容不限於 flex 本身,隨者 flex 的持續發展,將來 flex framework 也會用於 Apollo 與 Flashlite(mobile device), 並且它與 Ajax 的合作也會日益密切,所以取名為 flex-xxx 會略顯不足,才選定 RIA dev。
在可能的範圍內,我以及身邊的好友們會儘力參與討論並回覆問題,但就如同所有成功的討論區一般,一個群組的成敗主要還是取決於大家的參與度和熱情,希望有一天 RIADEV 也能成為像 flexcoders 一樣的優質群組。
RIADEV 使用方法基本上跟 flexcoders 一樣,可以透過
-web介面:直接在網頁上看討論與回覆
-email訂閱:加入此群組後就會每日收到討論信件(我個人比較喜歡這種方法,不用每天check website,只要有新信就會自動寄上門)
-rss feed:可以用 google reader 之類的 rss reader 訂閱(感謝 b6s 長輩提醒)
如果有使用上的問題歡迎留言發問。
ps. 目前群組中的舊文章皆已刪除,從今天起開始全新的討論。

by
Jeremy



想想也有我小小的功劳,至于什么是不会说的,^_^!
只不过有点不爽的是,他怎么能在星期六我在外面玩的时候更新自己的BLOG...

2007年2月1日星期四

The Flex documentation team招人

Requirements:


  1. Job Level Individual contributor

  2. Expertise Engineering-General

  3. Education Bachelors (or equivalent work experience)

  4. JobType Full Time

  5. Locale United States/San Francisco

  6. Experience 5-7 years

  7. Preferred Language English

为什么中国还没有这个机会呢?

Adobe Apollo FAQ Translate

为了spread Apollo, Adobe对Apollo FAQ进行了多国语言的翻译,已经有好多种语言了,欣喜的是其中包括我们的中文.

translated the Apollo FAQ into Chinese(中文)
translated the Apollo FAQ into PigLatin(拉丁文)
translated the Apollo FAQ into Greek(希腊文)
translated the Apollo FAQ into German(德语)
translated the Apollo FAQ into Swedish(瑞典语)
translated the Apollo FAQ into Japanese(日语)
translated the Apollo FAQ into Italian(意大利语)