Flex移动应用程序开发的技巧和窍门(三)
这是关于 Flex 移动应用程序开发的技巧和窍门系列文章的第三部分内容。第一部分内容主要集中讨论了视图之间以及应用程序执行之间切换时的数据处理。第二部分则主要涵盖了应用程序动作条和标签组件风格化方面的内容。在这一部分中,你将会学到如何控制动作条和标签组件的可见性,以及如何把标签组件移动到应用程序的顶端。
在使用基于 TabbedViewNavigatorApplication 的Flex移动应用程序的过程中,你可能需要隐藏动作条组件或标签组件。例如,在特定视图下,你可能想获取更大的屏幕空间,或者,你只是想根据个人喜好设置显示界面。在这些情况下,你可以使用 View 类中的两个有效的道具:actionBarVisible
以及tabBarVisible
,来达到预期的效果。
为了说明 actionBarVisible
和 tabBarVisible
究竟是如何工作的,我创建了一个简单的基于TabbedViewNavigatorApplication 的移动应用程序。如果你想查看完整的源代码,并亲自调试这个应用程序,下载这篇文章中用到的样本文件,并把项目导入到 Adobe Flash Builder 中去。
(这个应用程序的)代码中含有三个视图:View1,View2和View3。在第一个视图中含有控制ActionBar和TabBar可见性的按钮。
正如你在下面 View1 代码中看到的那样,你可以通过设置 actionBarVisible
和 tabBarVisible
为真
或假
来控制它们的可见性:
<?xml version="1.0" encoding="utf-8"?> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="View1"> <fx:Script> <![CDATA[ protected function onActionBarClickHandler(event:MouseEvent):void { if (actionBarVisible) { this.actionBarVisible = false; b.label="Show ActionBar"; } else { this.actionBarVisible = true; b.label="Hide ActionBar"; } } protected function onTabBarClickHandler(event:MouseEvent):void { if (tabBarVisible) { this.tabBarVisible = false; b2.label="Show TabBar"; } else { this.tabBarVisible = true; b2.label="Hide TabBar"; } } ]]> </fx:Script> <s:VGroup width="100%" height="100%" horizontalAlign="center" top="50"> <s:TextArea text="This is View 1" editable="false"/> <s:HGroup> <s:Button id="b" label="Hide ActionBar" click="onActionBarClickHandler(event)"/> <s:Button id="b2" label="Hide TabBar" click="onTabBarClickHandler(event)"/> </s:HGroup> </s:VGroup> </s:View>
当通过(点击)标签或程序控制来实现不同视图之间的切换时,这些项目的可见性只在View1中有所改变(如图1所示)。
其他视图不受影响(如图2所示)。
这并没有包含如下的主应用程序的代码:
<?xml version="1.0" encoding="utf-8"?> <s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"> <s:ViewNavigator label="View1" width="100%" height="100%" firstView="views.View1"/> <s:ViewNavigator label="View2" width="100%" height="100%" firstView="views.View2"/> <s:ViewNavigator label="View3" width="100%" height="100%" firstView="views.View3"/> </s:TabbedViewNavigatorApplication>
如果你亲自创建并测试这个应用程序,你会注意到,你隐藏了 ActionBar,切换到其他的视图,然后切换回 View1 时,动作条就会再次出现。之所以会有这样的情况出现,是因为当你再次把视图切换回来的时候,视图发生了重建。当你在特定的视图中,希望 ActionBar 一直处于隐藏状态,你可以通过几种不同的方法来实现。其中一种方法就是在视图中设置 destructionPolicy="never"
;这样 ActionBar 被隐藏之后就不会再自动重现,因为视图不会再自动重建。另一种方法是在根 View 标签中设置viewActivate="actionBarVisible=false"
,这样每次该视图被激活,ActionBar 都会处于隐藏状态。但是,使用这种方法存在的一个问题是,当这个视图被激活的时候,用户都会在视图隐藏之前,看到 ActionBar 短暂的出现,这可能是我们所不希望看到的。第三种方法是,在你的根选项卡应用程序文件中加入如下的代码,来设置 tabbedNavigator IndexChangeEvent
上的 ViewNavigator 组件中的当前视图actionBarVisible
属性为假
:
<?xml version="1.0" encoding="utf-8"?> <s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" applicationComplete="onApplicationComplete(event)"> <fx:Script> <![CDATA[ import mx.events.FlexEvent; import spark.events.IndexChangeEvent; protected function onApplicationComplete (event:FlexEvent):void{ vn1.actionBar.visible=false; tabbedNavigator.addEventListener(IndexChangeEvent.CHANGE,onChange); } protected function onChange(event:IndexChangeEvent):void { if (event.newIndex==0) vn1.activeView.actionBarVisible=false; } ]]> </fx:Script> <s:ViewNavigator id="vn1" label="View1" width="100%" height="100%" firstView="views.View1"/> <s:ViewNavigator label="View2" width="100%" height="100%" firstView="views.View2"/> <s:ViewNavigator label="View3" width="100%" height="100%" firstView="views.View3"/> </s:TabbedViewNavigatorApplication>
正如你在本文第二个示例应用程序中看到的那样,默认情况下,Flex 4.5 TabbedViewNavigatorApplication 的标签按钮是位于(应用程序的)底部的(如图3所示)。
但是,有的时候你可能更希望你的应用程序标签位于屏幕的顶端。
按照如下步骤,移动标签到你的应用程序的顶端:
- 找到并复制 TabbedViewNavigatorSkin.as 类到你的 mobile 项目目录 skins中去。在我的 Mac 上,我可以在如下目录中找到这个皮肤类(对 Flash Builder 4.5.1 而言):/Applications/Adobe Flash Builder 4.5/sdks/4.5.1/frameworks/projects/mobiletheme/src/spark/skins/mobile/TabbedViewNavigatorSkin.as。
- 要么在你的主应用文件中要么在一个外部样式表单中使用如下的皮肤类来设置你的CSS风格:
<fx:Style> @namespace s "library://ns.adobe.com/flex/spark"; s|TabbedViewNavigator { skinClass: ClassReference("skins.TabbedViewNavigatorSkin"); } </fx:Style>
- 在你新复制的 TabbedViewNavigatorSkin 类中,更改类顶部的 package 命令来反映它在你本地 skins文件夹中的新的位置;将 package 命令的第一行由
package spark.skins.mobile
替换为package skins
。 - 滚动鼠标至皮肤类底端,找到
layoutContents()
函数。这个函数是用来设置标签条和内容布局的。这里的内容指的是你的 View 类的子元素,例如,应用程序中的 UI 组件以及结果 List 等。
override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void { super.layoutContents(unscaledWidth, unscaledHeight); var tabBarHeight:Number = 0; if (tabBar.includeInLayout) { tabBarHeight = Math.min(tabBar.getPreferredBoundsHeight(), unscaledHeight); tabBar.setLayoutBoundsSize(unscaledWidth, tabBarHeight); tabBar.setLayoutBoundsPosition(0, unscaledHeight - tabBarHeight); tabBarHeight = tabBar.getLayoutBoundsHeight(); // backgroundAlpha is not a declared style on ButtonBar // TabbedViewNavigatorButtonBarSkin implements for overlay support var backgroundAlpha:Number = (_isOverlay) ? 0.75 : 1; tabBar.setStyle("backgroundAlpha", backgroundAlpha); } if (contentGroup.includeInLayout) { var contentGroupHeight:Number = (_isOverlay) ? unscaledHeight : Math.max(unscaledHeight - tabBarHeight, 0); contentGroup.setLayoutBoundsSize(unscaledWidth, contentGroupHeight); contentGroup.setLayoutBoundsPosition(0, 0); } }
在这里,关键是 tabBar.setLayoutBoundsPosition(x,y)
函数。如果你修改(这个函数)代码中的y
值为 0
,标签就会被置于应用程序的顶端:
if (tabBar.includeInLayout) { tabBarHeight = Math.min(tabBar.getPreferredBoundsHeight(), unscaledHeight); tabBar.setLayoutBoundsSize(unscaledWidth, tabBarHeight); tabBar.setLayoutBoundsPosition(0,0); tabBarHeight = tabBar.getLayoutBoundsHeight(); // backgroundAlpha is not a declared style on ButtonBar // TabbedViewNavigatorButtonBarSkin implements for overlay support var backgroundAlpha:Number = (_isOverlay) ? 0.75 : 1; tabBar.setStyle("backgroundAlpha", backgroundAlpha); } if (contentGroup.includeInLayout) { var contentGroupHeight:Number = (_isOverlay) ? unscaledHeight : Math.max(unscaledHeight - tabBarHeight, 0); contentGroup.setLayoutBoundsSize(unscaledWidth, contentGroupHeight); contentGroup.setLayoutBoundsPosition(0, 0); }
如果你想去掉动作条来制造更大的屏幕空间(如图5所示),你只需要进入 View 类并设置actionBarVisible
为 假
;例如:
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="Search Location..." actionBarVisible="false" xmlns:json="com.adobe.serialization.json.*" >