为了保障原创作者在本站发表文章的利益, 并维护本站原创的精神, 特声明: RIAShanghai对有以下任何情况之一的文章将不通知作者并直接进行快意删除:
- 非原创, 或者原创但一文多发;
- 各种形式的广告与吹擂;
- 不符合本站文章格式.
欢迎各位读者监督. 谢谢合作. 另: 作为Adobe正式的UG, 我们将把Adobe不定期分发的软件,书籍及各种纪念品赠送给发文活跃的作者, 共同进步.
也借此帖收收过年的心。
这个模仿是年前做的,最近整理代码,把它翻了出来。记得这个模仿,给Mr. J看过,他说被雷到了,这个题目就这么来了。
本作品模仿的是Windows Live Messenger 2009,当有好友登陆时,在屏幕右下方弹出的小窗口。
闲话少说,先上一张模仿好的效果图。
截图中浅紫色的那个窗体,是贴了个Messenger的截图,它位于主程序 mainApp.mxml中。
1. Native Window VS Window
右边两个蓝色的弹出窗口,是用户点击“Sign In”按钮后,弹出的两个蓝色窗口。这两个窗体是mx.core.Window部件。当然,这个弹出的窗体,也可以用flash.display.NativeWindow来实现。
之所以用mx.core.Window来实现,来看下我们下面这个对比。
| flash.display.NativeWindow | mx.core.Window | |
| Code Level | lower level API, not in “mx” namespace | higher level API, in “mx” namesapce |
| Relationship with Each Other | -- | UIComponent wrapper for NativeWindow |
| Initialization Property | -- | Note that several of the Window class's properties can only be set before calling the open() method to open the window. Once the underlying NativeWindow is created, these initialization properties can be read but cannot be changed. This restriction applies to the following properties:
|
| Way of Adding UIComponent Based Flex Component | Content can be added to a window using the DisplayObjectContainer methods of the Stage object such as addChild() e.g.
|
Content can be added directly e.g.
|
考虑到用得是Flex框架,那么我就选择mx.core.Window来实现我们的窗体,减少代码的复杂度。
2. 弹出窗口 InfoWin.mxml
让我来在代码中,解释其实现的原理
import com.chestnut.event.InfoCloseEvent;
private var destY:Number = new Number;
private var total:Number = 20;
private var timer:Timer;
/**
* 显示7秒后,窗体会自动消失
*/
private function onComp():void
{
timer = new Timer(7000,1);
timer.addEventListener(TimerEvent.TIMER, timerFinishHandler);
timer.start();
}
/**
* timer在第7秒时调用的方法
*/
private function timerFinishHandler(event:TimerEvent):void
{
//设置隐藏时要向下的位移
destY = this.nativeWindow.y + 30;
//在主时间轴上设置窗口隐藏的效果
this.addEventListener(Event.ENTER_FRAME, hideHandler);
}
/**
* 主时间轴上,窗体隐藏时要执行的方法
*/
private function hideHandler(event:Event):void
{
//检查窗口是否以达到隐藏时要求的位移
//如果没有达到,窗体就继续位移和变浅
if(this.nativeWindow.y < destY)
{
this.nativeWindow.y += 5;
this.alpha = 0.03 * total;
total -= 5;
}
//如果达到了隐藏时要求的位移,则出发窗体关闭的自定义事件,并去除主时间轴和timer的监听方程
else
{
var closeEvent:InfoCloseEvent = new InfoCloseEvent(InfoCloseEvent.INFO_WINDOW_CLOSED, true);
dispatchEvent(closeEvent);
this.removeEventListener(Event.ENTER_FRAME, hideHandler);
timer.removeEventListener(TimerEvent.TIMER, timerFinishHandler);
close();
}
}
/**
* 点击关闭按钮时要执行的方法
*/
private function btnCloseClicked():void
{
var event:InfoCloseEvent = new InfoCloseEvent(InfoCloseEvent.INFO_WINDOW_CLOSED, true);
dispatchEvent(event);
timer.removeEventListener(TimerEvent.TIMER, timerFinishHandler);
close();
}
在这里,主要是应用了Event.ENTER_FRAME的监听,把隐藏的效果放到主时间轴上进行实现。
3. 主窗体,mainApp.mxml,主要起到调用弹出窗口的作用
设置窗体的 system chrome, 可以参照本站Jack的 Quick Tip: Remove AIR Window Chrome Completely
有关实现自定义背景的,可以参照本站的 Flex程序实现背景贴图的两种方式 Two ways to implement sexy background/border for containers
下面是主窗体中的代码
import mx.containers.Canvas;
import mx.core.Window;
import mx.controls.FlexNativeMenu;
import mx.core.BitmapAsset;
import flash.display.NativeWindowSystemChrome;
import flash.display.NativeWindowType;
import com.chestnut.event.InfoCloseEvent;
[Embed(source="/assets/status_online.png")]
public var TrayImage:Class;
public var total:int = 0;
private var winArray:Array = new Array();
/**
* 主窗体初始化方法
*/
private function onInit():void
{
this.addEventListener(Event.CLOSE, closeHandler);
//设置一个系统托盘中的图标,截图中可以看到,是一个蓝色的小人
if(NativeApplication.supportsSystemTrayIcon)
{
var iconImg:BitmapAsset = BitmapAsset(new TrayImage());
NativeApplication.nativeApplication.icon.bitmaps = [iconImg];
var systemTrayIcon:SystemTrayIcon = NativeApplication.nativeApplication.icon as SystemTrayIcon;
systemTrayIcon.menu = createSystemTrayMenu();
}
}
/**
* 给托盘中的图标设置一个右键菜单
*/
private function createSystemTrayMenu():NativeMenu
{
var menu:NativeMenu = new NativeMenu();
var exitMenuItem:NativeMenuItem = new NativeMenuItem("退出 Exit");
menu.addItem(exitMenuItem);
return menu;
}
/**
* 如何弹出窗体,winArray中存有现有窗体的个数,弹出时,将根据是第几个窗体进行窗体位置的测试
*/
private function createInfoWindow():void
{
var infoWindow:InfoWin = new InfoWin();
infoWindow.systemChrome = NativeWindowSystemChrome.NONE;
infoWindow.type = NativeWindowType.LIGHTWEIGHT;
infoWindow.transparent = true;
infoWindow.open();
//窗体显示的动画效果,交由主时间轴的监听事件进行处理
infoWindow.addEventListener(Event.ENTER_FRAME, showWindowOption);
infoWindow.addEventListener(InfoCloseEvent.INFO_WINDOW_CLOSED, infoWindowCloseHandler);
//设置弹出窗体的初始位置
infoWindow.nativeWindow.x = Capabilities.screenResolutionX - 250;
infoWindow.nativeWindow.y = Capabilities.screenResolutionY - 100 - 180 * winArray.length;
winArray.push(infoWindow);
}
private function testBtnClicked():void
{
createInfoWindow();
}
/**
* 窗体显现时,要执行的方法
*/
private function showWindowOption(event:Event):void
{
var win:NativeWindow = (event.target as InfoWin).nativeWindow;
var targetIndex:int = winArray.indexOf(event.target as InfoWin);
//检查窗口是否到达了最终的显示位置
//如果没有,继续上移窗体,并在上移的过程中增加其透明度
if(win.y > Capabilities.screenResolutionY - 200 - 180 * targetIndex)
{
win.y -= 10;
(event.target as InfoWin).alpha = total * 0.01;
total = total + 10;
}
//如果位移到制定的位置了,那么去除掉主时间轴的监听
else
{
total = 0;
event.target.removeEventListener(Event.ENTER_FRAME, showWindowOption);
}
}
/**
* 关闭主窗体要执行的方法
*/
private function closeHandler(event:Event):void
{
for each(var win:InfoWin in winArray)
{
win.close();
}
}
/**
* 关闭一个弹出窗口时要执行的方法,删除掉弹出窗体在winArray中相对应的窗体
*/
private function infoWindowCloseHandler(event:InfoCloseEvent):void
{
var targetIndex:int = winArray.indexOf(event.target as InfoWin);
winArray.splice(targetIndex, 1);
}