Buzzword样式的右键菜单 Customized Context Menu as Buzzword
从 The Joy of Flex 的博客上,看到了一则关于 Buzzword的视频介绍。Buzzword是Adobe官方的一个线上文档编辑器。功能强大。
看到Buzzword的右键菜单很是好看,决定山寨一次,模仿一下。
通过模仿,我们可以了解如何制作一个Flex部件,自己来定义它的形状。
先上个Buzzword的右键菜单的视频截图,和模仿后的成品的截图。
左边的是视频截图,右边的是作者模仿。
Buzzword的那个Context Menu严格意义上来说,不是真正的,flash浏览器默认的那个右键菜单(就是有查看flash版本号选项的那个)。作者分析,那个Buzzword的这个context menu,不是基于flash.ui.ContextMenu来开发的。而是基于类似Canvas或者List一类的部件来进行开发的。作者是基于VBox来进行开发的。
这个Context Menu的特点就是,当鼠标沿着这个不规则的Context Menu四边游走的时候,被其盖在下面的部件,都能紧贴着Context Menu的边而被激活。也就是说,这个Context Menu的背景, 不是用一个这个不规则形状的截图来实现的。如果是这个形状的截图作为Context Menu的背景,那么作者放于这个Context Menu下面的Link Button 部件,就不会在鼠标放到该位置时,变成Mouse Over的状态。因为,这个按钮理应被正方形的截图所遮挡(之所以大家能看到它,是因为除了黑色的主体部分外,那个截图的画布背景是透明的)。
当然,如果不要求有上述这个功能,用截图也是可以的。但是这个部件的高度就不能方便地随意控制。
此次模仿的原理就是,自己写VBox的BorderSkin类。步骤如下,
1. 建立一个VBox的Border类,扩展mx.skins.Border类。覆盖 updateDisplayList方法。实现自己的graphics实例,也就是这个部件的外形了。
- package com.chestnut.view
- {
- import flash.display.Graphics;
- import flash.filters.DropShadowFilter;
- import mx.skins.Border;
- public class MyBorder extends Border
- {
- public function MyBorder()
- {
- super();
- }
- //覆盖updateDisplayList, 画自己所需要的图形
- override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
- {
- var g:Graphics = graphics;
- drawBorder(unscaledWidth, unscaledHeight, g, -5);
- }
- //覆盖drawBorder,画自定义的边
- public static function drawBorder(w:Number, h:Number, g:Graphics, inset:Number):void
- {
- var xSign:Number = 1;
- var ySign:Number = 1;
- var xShift:Number = 0;
- var yShift:Number = 0;
- var padding:Number = 20;
- var upperLeftControlOffset:Number = 5;
- var controlOffset:Number = 5;
- g.clear();
- g.beginFill(0x000000, 1);
- g.lineStyle(1, 0x000000, 1);
- //draw the menu
- g.moveTo(xShift+xSign*upperLeftControlOffset, yShift+ySign*inset);
- //..此处省略,这里就是Graphics,画出那个不规则图形的方法。代码因图形形状的不同而异,因此省略
- g.endFill();
- }
- }
- }
package com.chestnut.view { import flash.display.Graphics; import flash.filters.DropShadowFilter; import mx.skins.Border; public class MyBorder extends Border { public function MyBorder() { super(); } //覆盖updateDisplayList, 画自己所需要的图形 override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { var g:Graphics = graphics; drawBorder(unscaledWidth, unscaledHeight, g, -5); } //覆盖drawBorder,画自定义的边 public static function drawBorder(w:Number, h:Number, g:Graphics, inset:Number):void { var xSign:Number = 1; var ySign:Number = 1; var xShift:Number = 0; var yShift:Number = 0; var padding:Number = 20; var upperLeftControlOffset:Number = 5; var controlOffset:Number = 5; g.clear(); g.beginFill(0x000000, 1); g.lineStyle(1, 0x000000, 1); //draw the menu g.moveTo(xShift+xSign*upperLeftControlOffset, yShift+ySign*inset); //..此处省略,这里就是Graphics,画出那个不规则图形的方法。代码因图形形状的不同而异,因此省略 g.endFill(); } } }
2. 在CSS定义中,定义自己的borderSkin类。
- /* CSS file */
- .contextMenu{
- borderSkin: ClassReference("com.chestnut.view.MyBorder");
- }
/* CSS file */ .contextMenu{ borderSkin: ClassReference("com.chestnut.view.MyBorder"); }
3. 加入自己的 menu item 部件。
- private function onInit():void
- {
- menuArray = ["Open","Open in New Window","Seperator", "Share...", "Duplicate", "Rename", "Show Info", "Seperator", "Delete"];
- for each(var str:String in menuArray)
- {
- //当关键字是sperator时,就插入一个横线,vb就是VBox
- if(str == "Seperator")
- {
- var hr:HRule = new HRule();
- hr.width = 150;
- hr.setStyle("strokeColor", "#FFFFFF");
- hr.height = 1;
- vb.addChild(hr);
- }
- //其他时候,就插入自定义的menu item, 作者基于canvas来实现的
- else
- {
- var mi:MenuItem = new MenuItem();
- mi.menuStr = str;
- vb.addChild(mi);
- }
- }
- //加一个装饰阴影
- var sf:DropShadowFilter = new DropShadowFilter();
- sf.distance = 5;
- sf.alpha = 0.4;
- sf.angle = 45;
- vb.filters = [sf];
- var cm:ContextMenu = new ContextMenu();
- }
private function onInit():void { menuArray = ["Open","Open in New Window","Seperator", "Share...", "Duplicate", "Rename", "Show Info", "Seperator", "Delete"]; for each(var str:String in menuArray) { //当关键字是sperator时,就插入一个横线,vb就是VBox if(str == "Seperator") { var hr:HRule = new HRule(); hr.width = 150; hr.setStyle("strokeColor", "#FFFFFF"); hr.height = 1; vb.addChild(hr); } //其他时候,就插入自定义的menu item, 作者基于canvas来实现的 else { var mi:MenuItem = new MenuItem(); mi.menuStr = str; vb.addChild(mi); } } //加一个装饰阴影 var sf:DropShadowFilter = new DropShadowFilter(); sf.distance = 5; sf.alpha = 0.4; sf.angle = 45; vb.filters = [sf]; var cm:ContextMenu = new ContextMenu(); }