在Flex Mobile中构建“本地”菜单
Adobe Flash Builder 4 简体中文正式版 Windows版点击下载:http://g.csdn.net/5134151 Adobe Flash Builder 4 简体中文正式版 Mac版点击下载 :http://g.csdn.net/5134152 Adobe 在线课堂:http://adobev.csdn.net/zx/index.html Adobe平台技术峰会课程视频:http://adobev.csdn.net/? ? Flex?Mobile现在融合了本地Android?API的大部分内容及功能,从加速表,到工具栏,到传声器,构建一个本地化感觉的程序所需大部分功能都能轻松执行。有个例外就是缺省菜单组件。只要用户点击菜单按钮(在Android电话上的标准设置),这个菜单通常在屏幕底部就可见,并且包含一个程序特定菜单或根据用户使用的屏幕设计的特定菜单。 ? Flex?Mobile现在只有beta版,但是这个功能确定会出现在Android的路线图中,可能在完整版发出之前。同时,我将向你展示在Flex?Mobile上执行“本地”菜单的一个方法。我最近为Flex?Mobile构建了一个这样的菜单,作为我的MAX?Volume项目的一部分。MAX?Volume是一个“social?jukebox”,移动程序用户可浏览音乐库,并且选择他们想要听的下一首歌曲。我们的菜单首先用来在不同的视窗之间导航,每个视窗可以让用户整理或者根据个人喜好浏览音乐库。 ? 如需了解更多相关信息,你可以从Adobe?TV上的Adobe?MAX上阅读我们关于这个项目的presentation,并且可以了解更多此高级项目的信息,及如何开始使用Flex?Mobile。现在,我们开始这个Menu对象的制作。首先,你需要观察用户何时会点击Menu菜单。Menu现在在keyboard对象上是一个key,所以监听菜单事件很简单: ? this.view.addEventListener(KeyboardEvent.KEY_DOWN,?_onKeyDown); ? ? 监听功能: ? private?function?_onKeyDown(event:KeyboardEvent):void?{ ????if?(event.keyCode?==?Keyboard.MENU)?{ ????????//code?to?handle?the?menu?event?goes?here ????} } ? 在通常的网络或桌面程序中,这就是你需要的-监听事件,构建你的菜单对象。Flex?Mobil增加了复杂度,因为程序基本上是一个ViewStack对象,这就意味着你可能在任何给定时间有诸多不同的可视屏幕中的一个(只有一个)屏幕。你可以在每个屏幕上执行你的菜单(作为组件),但是这不是最理想的状态。大部分程序只需要一个全局菜单,及在需要高级菜单功能的单个屏幕上覆盖它的功能。全局菜单应该被执行一次,并且可从任何地址读取-重新执行该功能,即使它被构件化,“耗费“了我们为移动设备编程时,不能浪费的内存。那么,哪里放置菜单处理器?在Flex?Mobile中,基本程序对象是MobileApplication。它就在这里,我们将定义全局actionBar内容(屏幕顶部;程序标题),如一个标题或程序logo?.我认为,这也是为什么要监听菜单事件,执行我们的Menu对象。 ? 在MAX?Volume?中,我们使用Robotlegs?micro-architecture,?因此我们实际上要加入所需代码,以监听主程序mediator?class中的Menu点击事件。这个mediator包含一个对主MobileApplication类的参考,它负责构建Menu对象,将它插入在现用视窗的元素列表中。我的完整方法包括处理器,以覆盖后端和搜索按钮,所以如下所示: ? private?function?_onKeyDown(event:KeyboardEvent):void?{ if?(event.keyCode?==?Keyboard.BACK)?{ event.preventDefault(); }?else?if?(event.keyCode?==?Keyboard.MENU)?{ event.preventDefault(); view.toggleMenu(); }?else?if?(event.keyCode?==?Keyboard.SEARCH)?{ event.preventDefault(); } } ? event.preventDefault();?调用,当按钮按下时,阻止任何可能执行的内置Android功能。Back键可能导致Android系统“返回“,而“search”键可能执行全局搜索功能。阻止这些事件超出我们程序的控制,这样我们就可以有效地把它们控制在我们的上下文背景中。 ? 回到主MobileApplication视窗对象,触发菜单的代码比较复杂。 首先,我们需要将菜单从其它视窗移走。如果在不同的视窗中,菜单被打开,我们需要确保将菜单挪到我们现在的视窗前关闭该菜单。 下一步,我们需要根据菜单的状态隐藏或显示视窗。为此,我首先试图移走菜单。我使用了状态变量以跟踪最后发布菜单的视窗。有可能菜单不能移走,我会处理这个错误。当然,现在我没有在处理器中进行任何操作。我还使用了一个状态变量跟踪菜单是否可视。这个将菜单移走的过程在部分程度上重新设置了状态变量。 ? public?function?toggleMenu():void?{ //if?the?menu?is?visible?but?not?on?the?current?view,?hide?it?and?then?show?it?again if?(menuView?!=?null?&&?menuView?!=?this.navigator.activeView)?{d try?{ removeMenu(); }?catch?(e:Error)?{} showMenu(); }?else?if?(menuVisible)?{ hideMenu(); }?else?{ showMenu(); } }private?function?removeMenu(event:Event?=?null):void?{ menuView.removeElement(menu); menuVisible?=?false; } ? ? 在空的处理器中找出错误显然不是最佳策略。不过在开发过程中,我还是看到过此类错误。它没什么意义,不过是beta框架中的一个bug。菜单还是被移走了。我认为现在代码就不需要什么修改了。下一步,来看看我如何展示和隐藏菜单对象。 ? public?function?hideMenu():void?{ menuView.removeElement(menu); menuVisible?=?false; } ? public?function?showMenu():void?{ menuView?=?this.navigator.activeView; menu.y?=?menuView.height?-?menu.height; menuView.addElement(menu); menuVisible?=?true; } ? 这就是了。我在这个案例中执行的真实的菜单对象是一个简单的群对象,其中有四个按钮。菜单本身被调停(根据Robotlegs最佳策略),而这个mediator负责监听菜单中不同按钮上的点击事件。每个按钮将不同的视窗推入到主菜单导航栏中,这样我们的菜单就可只用于导航了。 菜单对象的代码如下所示: ? <?xml?version="1.0"?encoding="utf-8"?> <s:Group?xmlns:fx="http://ns.adobe.com/mxml/2009"?xmlns:s="library://ns.adobe.com/flex/spark"?height="209"?width="100%"> ????<s:VGroup?height="100%"?width="100%"> ????????<s:HGroup?height="100%"?width="100%"> ????????????<s:Button?id="songsBtn" ??????????????????????height="100%"?width="100%" ??????????????????????label="Songs"/> ????????????<s:Button?id="nowPlayingBtn" ??????????????????????height="100%"?width="100%" ??????????????????????label="Now?Playing"/> ????????</s:HGroup> ????????<s:HGroup?height="100%"?width="100%"> ????????????<s:Button?id="albumsBtn" ??????????????????????height="100%"?width="100%" ??????????????????????label="Albums"/> ????????????<s:Button?id="artistsBtn" ??????????????????????height="100%"?width="100%" ??????????????????????label="Artists"/> ????????</s:HGroup> ????</s:VGroup> </s:Group> ? 我的menu?mediator: ? package?com.effectiveui.maxpower.mobile.application.views.components?{ ? import?com.effectiveui.maxpower.mobile.application.models.MobileMusicModel; import?com.effectiveui.maxpower.mobile.application.views.AlbumsView; import?com.effectiveui.maxpower.mobile.application.views.ArtistsView; import?com.effectiveui.maxpower.mobile.application.views.SongsView; ? import?flash.events.Event; import?flash.events.MouseEvent; ? import?mx.collections.ArrayCollection; ? import?org.robotlegs.mvcs.Mediator; ? import?spark.components.View; ? public?class?MenuMediator?extends?Mediator?{ ? [Inject] public?var?view:Menu; ? [Inject] public?var?musicModel:MobileMusicModel; ? override?public?function?onRegister():void?{ eventMap.mapListener(view.artistsBtn,?MouseEvent.CLICK,?onArtists); eventMap.mapListener(view.albumsBtn,?onAlbums); eventMap.mapListener(view.songsBtn,?onSongs); eventMap.mapListener(view.nowPlayingBtn,?onNowPlaying); } ? private?function?onArtists(event:Event):void?{ (view.parent?as?View).navigator.popToFirstView(); (view.parent?as?View).navigator.pushView(ArtistsView); } ? private?function?onAlbums(event:Event):void?{ (view.parent?as?View).navigator.popToFirstView(); musicModel.currentAlbums?=?musicModel.safeAlbums; (view.parent?as?View).navigator.pushView(AlbumsView); } ? private?function?onSongs(event:Event):void?{ (view.parent?as?View).navigator.popToFirstView(); musicModel.currentAlbums?=?null; musicModel.currentSongs?=?musicModel.musicFiles; (view.parent?as?View).navigator.pushView(SongsView); } ? private?function?onNowPlaying(event:Event):void?{ (view.parent?as?View).navigator.popToFirstView(); } } } 有了这个系统,你的菜单就可以真正地包含任何来自简单的导航按钮的内容了,就如同那些高级UI组件,有自己的互动性。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |