很多学习AIR的同学都知道,这个几乎是不可能的,因为AIR有限的能力,还不能达到那种效果。
我曾今也单纯地以为,只要通过AS3的模糊滤镜,就能达到窗体磨砂的效果,答案是不行的,显然没那么简单,否则为啥市面上那么多AIR怎么就没有实现窗体磨砂的案例呢。如果单纯地通过AS3的模糊滤镜,可以实现舞台内部磨砂窗体,如果只是做子窗体效果,那也挺推荐用的。但现在要做的是顶级窗体的磨砂效果。
我曾今用C++成功实现过windows7下的磨砂,那是系统的窗体,通过createWindow()创建出来的,然后调用了微软在Vista版本以上系统才有的DWM库,该库可以让开发者轻松实现磨砂窗体,这里也不再赘述,详情请看牛人的文章http://blog.csdn.net/ntwilford/article/details/5656633
其实实现窗体磨砂并不难,难的是如何把这个技术用在AIR上面,其实这个也不怎么难,最难的是如何把AIR窗体的HWND句柄传给DLL,下面听我一步步道来。
先说如何把这个技术用在AIR上面,答案就是ANE,ANE是ADOBE为AIR开发的一个本地代码扩展功能,可以使用的语言有C/C++或者JAVA,如果是做windows应用开发的,那建议用C/C++(还有MAC OS 开发objective-c),如果做android应用开发的,那就用JAVA。本文用的C++,开发环境是VS2012(其实VS版本没啥关系,因为就使用VC库而已),系统是windows7旗舰版。这里需要注意的是,磨砂窗体需要Vista及以上的系统内核才支持的,否则会提示缺少DLL,就算有了DLL,也会出不来效果。还有就是需要主题开启Aero效果,这是废话?有些开发者为了使系统达到一定的开发效率,就把Aero关掉了,现在开启吧。本人的是台式机,Aero效果无压力。
废话不多说了,看代码:
1 package 2 { 3 import flash.display.NativeWindow; 4 import flash.external.ExtensionContext; 5 /** 6 * 7 * @author RockyF 8 * 磨砂窗体类,首先必须通过bindWindow来绑定一个窗体(为了提高效率,采用了先绑定的方案) 9 */ 10 public class BlurWindow 11 { 12 private var context:ExtensionContext; 13 public function BlurWindow() 14 { 15 context = ExtensionContext.createExtensionContext("BlurWindow",""); 16 } 17 18 /** 19 * 绑定窗体句柄,以提高效率 20 * @param window 要应用磨砂窗体的NativeWindow对象 21 * @return 22 * 23 */ 24 public function bindWindow(window:NativeWindow):Boolean{ 25 var titleOld:String = window.title; 26 27 var titleNew:String = ""; 28 29 var chars:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 30 for(var i:int = 0; i < 20; i++){ 31 titleNew += chars.charAt(int(Math.random() * 26)); 32 } 33 window.title = titleNew; 34 35 var result:Boolean = Boolean(context.call("bindWindow", titleNew)); 36 37 window.title = titleOld; 38 39 return result; 40 } 41 42 /** 43 * 你无需传入窗体的句柄,只需要提供要应用磨砂窗体的NativeWindow对象 44 * 45 * @param padding 该磨砂窗体的内边距,这个参数在设置窗体阴影的时候很重要 46 * @param radius 磨砂窗体的圆角半径 47 * @return 返回结果该系统是否支持磨砂窗体 48 * 49 */ 50 public function apply(padding:int, radius:int):void{ 51 context.call("apply", padding, padding, padding, padding, radius, radius) 52 } 53 54 /** 55 * 你无需传入窗体的句柄,只需要提供要应用磨砂窗体的NativeWindow对象 56 * 57 * @param padding 该磨砂窗体的内边距,这个参数在设置窗体阴影的时候很重要 58 * @param radius 磨砂窗体的圆角半径 59 * @return 返回结果该系统是否支持磨砂窗体 60 * 61 */ 62 public function applyAdvance(paddingLeft:int, paddingTop:int, paddingRight:int, paddingBottom:int, radiusX:int, radiusY:int):void{ 63 context.call("apply", paddingLeft, paddingTop, paddingRight, paddingBottom, radiusX, radiusY); 64 } 65 /** 66 * 判断该系统是否支持磨砂窗体 67 * @return 返回结果该系统是否支持磨砂窗体 68 * 69 */ 70 public function isSupported():Boolean{ 71 var ispt:Boolean = Boolean(context.call("isSupported")); 72 return ispt; 73 } 74 } 75 }
该类提供了四个方法和一个构造方法,构造方法是要的,通过构造方法创建一个上下文环境context, 以后对DLL的调用都会通过这个context(具体了解ANE,可以查看ADOBE官方文档,这里不再赘述了)。
在new了这个类之后,需要绑定一个AIR窗体,为啥要绑定?我也是通过很多地试验得出的结论,每次都要获取AIR窗体的句柄,何不就获取一次,然后保留在DLL中呢,这样的话,每次apply一次窗体,都不会做同样的事了。
看到这里,有人就要问了,这么多废话,那个AIR窗体的句柄到底怎么传递给DLL啊?
记得我在论坛回复道:拐几个弯就行了。我猜那位兄弟是理解了我的话,然后,他就动用了WIN 32 api大军,从进程到模块,都用了遍,最后还是得不到句柄。
现在就公布答案:WIN 32 API那么多,何愁得不到一个窗体的句柄。其实,在BlurWindow这个类中,就可以看到如何传递句柄了,我就是用了窗体的title属性,很容易联想到吧,在c++端就是接收了这个title,然后通过FindWindow()来获得句柄的。然而,又有人要问,那如果有同名的窗体,那怎么办?看代码中,我拐了一个弯:我先把原窗体的title存下来,然后用一个随机的20个字母的字符串来覆盖掉,可想而知,随机的20个字母组成的字符串,要碰到相同的title,那几率是多少,很小很小,所以我忽略不计了。如果你要还是担心会重名,那建议你用MD5好了。
好了,关键的技术点我已经放出来,有意向的同学就可以开始动手了。
要是懒得动啊,那下载源码好了。源码中的效果图:
转载请注明:http://www.cnblogs.com/rockyf/archive/2013/03/11/AIR_Win7_BlurWindow.html
源码下载:
BlurWindow.zip flash pro版
BlurWindow.zip flash builder版