在移动设备应用程序中,callout 是在应用程序顶部弹出的容器。该容器可以容纳一个或多个组件,并且支持不同类型的布局。
callout 容器可以是模态或非模态容器。模态容器在其关闭之前接受所有的键盘和鼠标输入。非模态容器允许应用程序中的其它组件在该容器处于打开状态时接受输入。
Flex 提供了两个可用于将 callout 容器添加到移动设备应用程序中的组件:CalloutButton 和 Callout。
CalloutButton 控件提供了一种创建 callout 容器的简单方式。通过该组件,您可以定义显示在 callout 中的组件和设置容器布局。
在移动设备应用程序中选择 CalloutButton 控件时,该控件将打开 callout 容器。Flex 会自动绘制一个从 callout 容器指向 CalloutButton 控件的箭头,如下图所示:
以下示例说明了用于创建上图中显示的 CalloutButton 的移动设备应用程序:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobileviewsCalloutButtonSimpleHomeView.mxml --> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"> <s:layout> <s:VerticalLayout paddingLeft="10" paddingTop="10"/> </s:layout> <s:Label text="Select the button to open the callout"/> <s:CalloutButton id="myCB" horizontalPosition="end" verticalPosition="after" label="Open callout"> <s:calloutLayout> <s:HorizontalLayout/> </s:calloutLayout> <!-- Define buttons that appear in the callout. --> <s:Button label="OK" click="myCB.closeDropDown();"/> <s:Button label="Cancel" click="myCB.closeDropDown();"/> </s:CalloutButton> </s:View>
CalloutButton 控件定义显示在 callout 容器内的两个 Button 控件。CalloutButton 控件还指定将 HorizontalLayout 用作 callout 容器的布局。默认情况下,该容器使用 BasicLayout。
使用 CalloutButton 控件打开和关闭 Callout 容器
当用户选择 CalloutButton 控件或您调用 CalloutButton.openDropDown() 方法时,callout 容器将打开。horizontalPosition 和 verticalPosition 属性确定 callout 容器相对于 CalloutButton 控件的位置。有关示例,请参阅确定 callout 容器的大小和位置。
CalloutButton 打开的 callout 容器始终都是非模态的。这意味着应用程序中的其它组件可以在 callout 处于打开状态时接受输入。使用 Callout 容器创建模态 callout。
在您单击 callout 容器以外的位置或调用 CalloutButton.closeDropDown() 方法之前,callout 容器一直处于打开状态。在该示例中,对于 callout 容器中两个 Button 控件的 click 事件,您在事件处理函数中调用了 closeDropDown() 方法。
使用 Callout 容器创建 callout
CalloutButton 控件将 callout 容器以及打开和关闭 callout 必需的所有逻辑封装在一个控件中。则 CalloutButton 控件成为 callout 容器的主机。
您还可以在移动设备应用程序中使用 Callout 容器。Callout 容器的好处是它不与单个主机关联,因此可以重用于应用程序中的任何位置。
通常,为了响应事件,使用 Callout.open() 和 Callout.close() 方法打开 Callout 容器。调用 open() 方法时,可以传递可选参数以指定调用容器为模态容器。默认情况下,调用容器为非模态容器。
调用容器的位置相对于主机组件。horizontalPosition 和 verticalPosition 属性确定容器相对于主机的位置。有关示例,请参阅确定 callout 容器的大小和位置。
由于它为弹出窗口,因此不能创建一个 Callout 容器作为应用程序的正常 MXML 布局代码的一部分。应在 MXML 文件中将 Callout 容器定义为自定义 MXML 组件。
在以下示例中,在应用程序的 comps 目录的 MyCallout.mxml 文件中定义 Callout 容器:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobilecompsMyCallout.mxml --> <s:Callout xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" horizontalPosition="start" verticalPosition="after"> <s:VGroup paddingTop="10" paddingLeft="5" paddingRight="10"> <s:HGroup verticalAlign="middle"> <s:Label text="First Name: " fontWeight="bold"/> <s:TextInput width="225"/> </s:HGroup> <s:HGroup verticalAlign="middle"> <s:Label text="Last Name: " fontWeight="bold"/> <s:TextInput width="225"/> </s:HGroup> <s:HGroup> <s:Button label="OK" click="close();"/> <s:Button label="Cancel" click="close();"/> </s:HGroup> </s:VGroup> </s:Callout>
MyCallout.mxml 定义一个简单的弹出窗口以允许用户输入名和姓。请注意,按钮调用 close() 方法关闭 callout 以响应 click 事件。
以下示例说明了用于打开 MyCallout.mxml 的 View 容器以响应 click 事件:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobileviewsCalloutSimpleHomeView.mxml --> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"> <s:layout> <s:VerticalLayout paddingLeft="10" paddingTop="10"/> </s:layout> <fx:Script> <![CDATA[ import comps.MyCallout; // Event handler to open the Callout component. protected function button1_clickHandler(event:MouseEvent):void { var myCallout:MyCallout = new MyCallout(); // Open as a modal callout. myCallout.open(calloutB, true); } ]]> </fx:Script> <s:Label text="Select the button to open the callout"/> <s:Button id="calloutB" label="Open Callout container" click="button1_clickHandler(event);"/> </s:View>
首先,将 MyCallout.mxml 组件导入至应用程序。为了响应 click 事件,名为 calloutB 的按钮创建了一个 MyCallout.mxml 实例,然后调用 open() 方法。
open() 方法指定两个参数。第一个参数指定 calloutB 是 callout 的主机组件。因此,callout 在应用程序中将自身定位在相对于 calloutB 位置的位置。第二个参数为 true 以创建模态 callout。
定义内联 callout 容器
您无需在单独文件中定义 Callout 容器。以下示例使用 <fx:Declaration> 标签将其定义为 View 容器的内联组件:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobileviewsCalloutInlineHomeView.mxml --> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"> <s:layout> <s:VerticalLayout paddingLeft="10" paddingTop="10"/> </s:layout> <fx:Script> <![CDATA[ // Event handler to open the Callout component. protected function button1_clickHandler(event:MouseEvent):void { var myCallout:MyCallout = new MyCallout(); // Open as a modal callout. myCallout.open(calloutB, true); } ]]> </fx:Script> <fx:Declarations> <fx:Component className="MyCallout"> <s:Callout horizontalPosition="end" verticalPosition="after"> <s:VGroup paddingTop="10" paddingLeft="5" paddingRight="10"> <s:HGroup verticalAlign="middle"> <s:Label text="First Name: " fontWeight="bold"/> <s:TextInput width="225"/> </s:HGroup> <s:HGroup verticalAlign="middle"> <s:Label text="Last Name: " fontWeight="bold"/> <s:TextInput width="225"/> </s:HGroup> <s:HGroup> <s:Button label="OK" click="close();"/> <s:Button label="Cancel" click="close();"/> </s:HGroup> </s:VGroup> </s:Callout> </fx:Component> </fx:Declarations> <s:Label text="Select the button to open the callout"/> <s:Button id="calloutB" label="Open Callout container" click="button1_clickHandler(event);"/> </s:View>
从 Callout 容器中传回数据
使用 Callout 容器的 close() 方法将数据传回主应用程序。close() 方法具有如下签名:
public function close(commit:Boolean = false, data:*):void
-
如果应用程序应提交返回的数据,则 commit 包含 true。
-
data 指定返回的数据。
调用 close() 方法会分派 close 事件。与 close 事件关联的事件对象是类型为 spark.events.PopUpEvent 的对象。PopUpEvent 类定义两个属性:commit 和 data,这两个属性包含 close() 方法的相应参数值。在 close 事件的事件处理函数中使用这些属性,以便检查从 callout 返回的任何数据。
callout 容器是 SkinnablePopUpContainer 类的子类,它使用相同的机制将数据传回主应用程序中。有关从 SkinnablePopUpContainer 容器传回数据的示例,请参阅从 Spark SkinnablePopUpContainer 容器传回数据。
以下示例将修改如上所示的 Callout 组件以返回名和姓值:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobilecompsMyCalloutPassBack.mxml --> <s:Callout xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" horizontalPosition="start" verticalPosition="after"> <fx:Script> <![CDATA[ import spark.events.IndexChangeEvent; public var retData:String = new String(); // Event handler for the click event of the OK button. protected function clickHandler(event:MouseEvent):void { //Create the return data. retData = firstName.text + " " + lastName.text; // Close the Callout. // Set the commit argument to true to indicate that the // data argument contains a valid value. close(true, retData); } ]]> </fx:Script> <s:VGroup paddingTop="10" paddingLeft="5" paddingRight="10"> <s:HGroup verticalAlign="middle"> <s:Label text="First Name: " fontWeight="bold"/> <s:TextInput id="firstName" width="225"/> </s:HGroup> <s:HGroup verticalAlign="middle"> <s:Label text="Last Name: " fontWeight="bold"/> <s:TextInput id="lastName" width="225"/> </s:HGroup> <s:HGroup> <s:Button label="OK" click="clickHandler(event);"/> <s:Button label="Cancel" click="close();"/> </s:HGroup> </s:VGroup> </s:Callout>
在该示例中,创建 String 返回名和姓,以对用户选择“确定”按钮做出响应。
View 容器然后使用 Callout 中的 close 事件以显示返回的数据:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobileviewsCalloutPassBackDataHomeView.mxml --> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"> <s:layout> <s:VerticalLayout paddingLeft="10" paddingTop="10"/> </s:layout> <fx:Script> <![CDATA[ import comps.MyCalloutPassBack; import spark.events.PopUpEvent; public var myCallout:MyCalloutPassBack = new MyCalloutPassBack(); // Event handler to open the Callout component. protected function clickHandler(event:MouseEvent):void { // Add an event handler for the close event to check for // any returned data. myCallout.addEventListener('close', closeHandler); // Open as a modal callout. myCallout.open(calloutB, true); } // Handle the close event from the Callout. protected function closeHandler(event:PopUpEvent):void { // If commit is false, no data is returned. if (!event.commit) return; // Write the returned Data to the TextArea control. myTA.text = String(event.data); // Remove the event handler. myCallout.removeEventListener('close', closeHandler); } ]]> </fx:Script> <s:Label text="Select the button to open the callout"/> <s:Button id="calloutB" label="Open Callout container" click="clickHandler(event);"/> <s:TextArea id="myTA"/> </s:View>
将 ViewNavigator 添加到 Callout 中
您可以在 Callout 容器中使用 ViewNavigator。通过 ViewNavigator 可以向 callout 中添加操作栏和多个视图。
例如,以下 View 打开了在文件 MyCalloutPassBackVN 中定义的 Callout 容器:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobileviewsCalloutPassBackDataHomeView.mxml --> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"> <s:layout> <s:VerticalLayout paddingLeft="10" paddingTop="10"/> </s:layout> <fx:Script> <![CDATA[ import comps.MyCalloutPassBackVN; import spark.events.PopUpEvent; public var myCallout:MyCalloutPassBackVN = new MyCalloutPassBackVN(); // Event handler to open the Callout component. protected function clickHandler(event:MouseEvent):void { myCallout.addEventListener('close', closeHandler); myCallout.open(calloutB, true); } // Handle the close event from the Callout. protected function closeHandler(event:PopUpEvent):void { if (!event.commit) return; myTA.text = String(event.data); myCallout.removeEventListener('close', closeHandler); } ]]> </fx:Script> <s:Label text="Select the Open button to open the callout"/> <s:TextArea id="myTA"/> <s:actionContent> <s:Button id="calloutB" label="Open" click="clickHandler(event);"/> </s:actionContent> </s:View>
MyCalloutPassBackVN.mxml 文件定义用于容纳 ViewNavigator 容器的 Callout 容器:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobilecompsMyCalloutVN.mxml --> <s:Callout xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" contentBackgroundAppearance="none" horizontalPosition="start" verticalPosition="after"> <fx:Script> <![CDATA[ import mx.events.FlexMouseEvent; import views.SettingsView; protected function done_clickHandler(event:MouseEvent):void { // Create an instance of SettingsView, and // initialize it as a copy of the current View of the ViewNavigator. var settings:SettingsView = (viewNav.activeView as SettingsView); // Create the String to represent the returned data. var retData:String = new String(); // Initialze the String from the current View. retData = settings.firstName.text + " " + settings.lastName.text; // Close the Callout and return thhe data. this.close(true, retData); } ]]> </fx:Script> <s:ViewNavigator id="viewNav" width="100%" height="100%" firstView="views.SettingsView"> <s:navigationContent> <s:Button label="Cancel" click="close(false)"/> </s:navigationContent> <s:actionContent> <s:Button id="done" label="OK" emphasized="true" click="done_clickHandler(event);"/> </s:actionContent> </s:ViewNavigator> </s:Callout>
在 MyCalloutPassBackVN.mxml 中,指定 ViewNavigator 的第一个视图是 SettingsView。SettingsView 定义针对用户名字和姓氏的 TextInput 控件。用户选择“确定”按钮时,将关闭 Callout 并将任何返回数据传回 MyCalloutPassBackVN。
下图显示在 Callout 处于打开状态下的应用程序:
SettingsView.mxml 如下所示:
<?xml version="1.0" encoding="utf-8"?> <!-- componentsmobileviewsSettingsView.mxml --> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="Settings"> <s:VGroup paddingTop="10" paddingLeft="5" paddingRight="10"> <s:HGroup verticalAlign="middle"> <s:Label text="First Name: " fontWeight="bold"/> <s:TextInput id="firstName" width="225"/> </s:HGroup> <s:HGroup verticalAlign="middle"> <s:Label text="Last Name: " fontWeight="bold"/> <s:TextInput id="lastName" width="225"/> </s:HGroup> </s:VGroup> </s:View>
确定 callout 容器的大小和位置
CalloutButton 控件和 Callout 容器使用以下两个属性指定 callout 容器相对于其主机的位置:horizontalPosition 和 verticalPosition。这两个属性可以具有下列值:“before”、“start”、“middle”、“end”、“after”和“auto”(默认值)。
例如,按照如下所示的方式设置这两个属性:
horizontalPosition="before" verticalPosition="after"
callout 容器将在主机组件的左下方打开。如果按照如下所示的方式设置这两个属性:
horizontalPosition="middle" verticalPosition="middle"
callout 容器将在主机组件的顶部打开,callout 的中心与主机组件的中心对齐。
绘制一个从 Callout 指向主机的箭头
对于除 horizontalPosition 与 verticalPosition 属性的五种组合之外的所有位置,callout 都会绘制一个指向主机的箭头。当 Callout 位于主机中部上方居中以及角落时,不会显示箭头。以下组合不显示箭头:
// Centered horizontalPosition="middle" verticalPosition="middle" // Upper-left corner horizontalPosition="before" verticalPosition="before" // Lower-left corner horizontalPosition="before" verticalPosition="after" // Upper-right corner horizontalPosition="after" verticalPosition="before" // Lower-right corner horizontalPosition="after" verticalPosition="after"
对于 Callout 容器,horizontalPosition 和 verticalPosition 属性还确定 Callout.arrowDirection 只读属性的值。callout 容器相对于主机的位置确定 arrowDirection 属性的值。可能的值包括 "up"、"left" 和其它。
Callout.arrow 外观部件使用 arrowDirection 属性的值基于 callout 位置绘制箭头。
管理 callout 容器的内存
使用 callout 容器时的一个注意事项是如何管理 callout 使用的内存。例如,如果希望减少应用程序使用的内存,则在每次打开应用程序时创建 callout 的实例。然后,在应用程序关闭时破坏 callout。但是,确保删除 callout(尤其是事件处理函数)的所有引用,否则 callout 不会被破坏。
或者,如果 callout 容器相对比较小,则可以在应用程序中多次重用相同的 callout。在该配置中,应用程序创建单个 callout 实例。然后,它重用该实例,callout 在使用的间隔保留在内存中。该配置减少了在应用程序中的执行时间,因为应用程序无需在每次打开时重新创建 callout。
使用 CalloutButton 控件管理内存
要配置 CalloutButton 控件使用的 callout,请设置 CalloutButton.calloutDestructionPolicy 属性。"auto" 的值配置在 callout 关闭时将其破坏的控件。"never" 的值配置将 callout 缓存在内存中的控件。
使用 Callout 容器管理内存
Callout 容器不定义 calloutDestructionPolicy 属性,而是按照您在应用程序中创建 callout 容器实例的方式控制其内存使用。在以下示例中,将在每次打开 callout 容器时创建它的实例:
protected function button1_clickHandler(event:MouseEvent):void { // Create a new instance of the callout container every time you open it. var myCallout:MyCallout = new MyCallout(); myCallout.open(calloutB, true); }
或者,也可以定义在每次打开 callout 容器时重用的单个 callout 容器实例:
// Create a single instance of the callout container. public var myCallout:MyCallout = new MyCallout(); protected function button1_clickHandler(event:MouseEvent):void { myCallout.open(calloutB, true); }