In Alloy, the XML markup abstracts the Titanium SDK UI components, so you do not need to code the creation and setup of these components using JavaScript and the Titanium SDK API. All view files must be placed in the app/views folder of your project with the ‘.xml’ file extension. During code compilation, Alloy looks for these markup files in this specific location to transform them into Titanium code, which can be executed by Studio and the CLI.
The following code is an example of a view file:
app/views/index.xml <Alloy> <Window class="container"> <Label id="label" onClick="doClick">Hello, World</Label> </Window></Alloy>The Alloy tag is the root element for the XML markup and is required in all views. The Window element defines an instance of the Ti.UI.Window object and within that window instance is the Label element, which defines an instance of a Ti.UI.Label object. Almost all of the Alloy XML tags are the class names of the Titanium UI components without the preceding namespace. Exceptions to this rule are listed in the Element table below.
Within a controller, a UI component can be referenced if its ID attribute is defined. For instance, the Label component in the above example has its ID defined as ‘label’ and can be referenced in the controller using $.label.
If the top-level UI component does not have an ID defined, it can be referenced using the name of the view-controller prefixed with a dollar sign and period (‘$.’). For instance, the Window element in the above example can be referenced in the controller using $.index.
The following code is how you would traditionally code the markup example using the Titanium SDK:
Resources/app.jsvar win = Ti.UI.createWindow();var label = Ti.UI.createLabel({text: 'Hello, World'});label.addEventListener('click', doClick);win.add(label);In the previous example, the win.open call and implementation of the doClick callback are missing. In Alloy, your JavaScript code and Titanium API calls need to be placed in the associated controller file to the view. For this example, the code would need be placed in app/controllers/index.js.
The following table lists the attributes for the UI components:
The following table lists the special XML elements besides the Titanium UI components:
index.xml is a special case that only accepts the following view components as direct children of the Alloy tag:
Other views do not have any format restrictions.
For examples, refer to the ‘Alloy XML Markup’ examples in the Titanium API Guides site. Most examples are in the components under the Titanium.UI section and also in Titanium.Android.Menu, Titanium.Facebook.LoginButton, Titanium.Map and Titanium.Media.VideoPlayer.
The Require XML element has two uses: including external views and importing widgets into the current view.
Including Views
Views may be included in other views using the Require element. Specify the type attribute as ‘view’ and the src attribute should be the view file minus the ‘.xml’ extension, and assign a unique value to the id attribute to reference the UI objects in the controller code. If you omit the type attribute, Alloy assumes it is implicitly set to ‘view’.
The example below creates a tab group in the main view file and includes two separate files for each tab.
Contents of the main view file (index.xml) that includes the rss and about views:
<Alloy> <TabGroup> <Tab id="leftTab"> <Require type="view" src="rss" id="rssTab"/> </Tab> <Tab id="rightTab"> <Require type="view" src="about" id="aboutTab"/> </Tab> </TabGroup></Alloy>Contents of the rss view file (rss.xml):
<Alloy> <Window id='rssWindow'> <WebView id='rssView' /> </Window></Alloy>Contents of the about view file (about.xml):
<Alloy> <Window id='aboutWindow'> <WebView id='aboutView' /> </Window></Alloy>To use UI objects from the included views, the controller needs to reference the ID specified in the Require element and use the getView function with the ID of the object as the argument: var object = $.requireId.getView(‘objectId’). The code below demonstrates how to access the web view object from the about view, in the previous example code, to change the URL property.
var aboutView = $.aboutTab.getView('aboutView'); aboutView.url = 'http://www.google.com';Importing Widgets
Within a view in the regular Alloy project space (app/views), use the <Widget> tag to import the widget into the application. A <Widget/> element is equivalent to a <Require/> element whose type attribute is set to “widget”.
To import a widget:
You can optionally add the id and name attributes to the Require element:
For example, to import the mywidget widget in to a project, copy mywidget to the app/widgets folder.
app├── config.json├── controllers│ └── index.js├── views│ └── index.xml└── widgets └── mywidget ├── controllers │ ├── foo.js │ └── widget.js ├── views │ ├── foo.xml │ └── widget.xml └── widget.jsonThen, add the <Widget> tag in the XML markup. Specify the src attribute as mywidget. Additionally, define the id and name attributes. Since the name attribute is defined, the foo view-controller is used instead of the widget view-controller.
app/views/index.xml<Alloy> <Window> <Widget src="mywidget" id="foo" name="foo" /> </Window></Alloy>Since the id attribute is defined, the widget can be accessed from the controller.
app/controllers/index.js$.index.open();$.foo.myMethod();Finally, update the dependencies object in the config.json file by adding a key/value pair with the mywidget as the key and the 1.0 as the value:
..."dependencies": {"mywidget":"1.0" }Passing Arguments
You can add any custom attributes to the markup to initialize a widget or controller. For example, consider the following mark-up:
apps/views/index.xml<Require id="foobar" src="foo" customTitle="Hello" customImage="hello.png"/>This is equivalent to the following JavaScript:
apps/controllers/index.jsvar foobar = Alloy.createController('foo', { id: "foobar", customTitle: "Hello", customImage: "hello.png" });In the required view’s controller, the custom properties can be referenced using the arguments[0] variable, for example:
apps/controllers/foo.jsvar args = arguments[0] || {}var title = args.customTitle || 'Foobar';var image = args.customImage || 'default.png';See Alloy Controllers: Passing Arguments for more details.
Binding Events
To bind a callback to an event in a required view using the on attribute as detailed in Event Handling below, add an event listener for the UI component to trigger the event. For example, suppose you want to require a view that only contains a button. In the parent view, you require the button view and assign a callback to the click event:
Parent View:
<Require id="fooButton" src="button" onClick="doClick" />Button View:
<Alloy> <Button id="button">Click Me!</Button></Alloy>The doClick method is defined in the parent’s controller.
In the controller of the required view, you need to define an event listener that triggers the event for the parent view to receive:
$.button.addEventListener('click', function(e) { $.trigger('click', e); });When the button is clicked in the parent view, the controller code in the required view fires a click event, which is caught by the parent view and executes the doClick method.
Adding Children Views
Since Alloy 1.3.0, if your Require element is a parent view, you can add children elements to it. These children elements are passed to the parent controller as an array called arguments[0].children. Use this array to access the children views to add them to the parent.
In the example below, you have the index view which is using the Require element to include another view called info. The required view is a yellow box with a brown border. Its controller adds the label view element passed in as the first element of the arguments[0].children array.
app/views/info.xml<Alloy> <View backgroundColor="yellow" borderWidth="0.5" borderColor="brown"/></Alloy>controllers/info.jsvar args = arguments[0] || {};// add children if there are any_.each(args.children || [], function(child) { $.info.add(child);});$.info.height = Ti.UI.SIZE;app/views/index.xml<Alloy> <Window class="container"> <Require src="info"> <Label>I am an info box.</Label> </Require> </Window></Alloy>By default, all UI components specified in the views are prefixed with Titanium.UI for convenience. However, to use a component not part of the Titanium.UI namespace, use the ns attribute. For example, to use the Titanium.Map.View, do:
<View ns="Ti.Map" id="map"/>For UI objects that belong to a specific platform, such as the navigation window. Use the platform attribute to use the object, for example:
<NavigationWindow platform="ios"/>Many of the Titanium view proxies not part of the Titanium.UI namespace do not require that the ns attribute be explicitly set. The following elements are implicitly mapped to a namespace if one is not defined:
Add the platform, formFactor and if attributes to apply XML elements based on conditionals.
You can use all the attributes in combination.
In the example below, different Annotation objects are displayed in the view based on the platform and device size.
<Alloy> <Window> <Module id="mapview" module="ti.map" method="createView"> <Annotation title="Cupertino" platform='ios' formFactor='tablet' latitude='37.3231' longitude='-122.0311'/> <Annotation title="Redwood City" platform='ios' formFactor='handheld' latitude='37.4853' longitude='-122.2353'/> <Annotation title="Mountain View" platform='android' latitude='37.3861' longitude='-122.0828'/> <Annotation title="Palo Alto" platform='android,ios,mobileweb' latitude='37.4419' longitude='-122.1419'/> <Annotation title="San Francisco" platform='mobileweb' latitude='37.7750' longitude='-122.4183'/> </View> </Window></Alloy>You can also create subfolders, named as the platform, in the views directory as another way to create platform-specific views. Refer to Alloy Concepts: Platform-Specific Resources.