[L4] Cross-platform - Titanium UI

Transcript

[L4] Cross-platform - Titanium UI
Università Degli Studi di Parma
Distributed Systems Group
Cross-platform Programming
Lecture 4
Titanium User Interface
Alessandro Grazioli
http://dsg.ce.unipr.it/?q=node/37
http://dsg.ce.unipr.it/
Alessandro Grazioli
[email protected]
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
Overview
User Interface elements
‣
View
‣
Window
‣
Animation
‣
Label
‣
WebView
‣
Picker
‣
TableView, TableViewRow and SearchBar
‣
ListView
‣
ProgressBar
‣
ScrollView
‣
Tab and TabGroup
Alessandro Grazioli
‣
Forms
‣
Switch
‣
Slider
‣
ListView, ListSection, ListItem
‣
ImageView
‣
EmailDialog
‣
Button
‣
AlertDialog
‣
Icons and splash screen
‣
Hiding the title bar on Android
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Elements
-
UI elements are defined in Titanium.Proxy → Titanium.Module → Titanium.UI
‣
Titanium.Proxy is the base for all Titanium objects
•
‣
A proxy represents a wrapper around a native object and thus, calling a method on a proxy object
results in a method invocation on a native object
Titanium.Module is the base for all Titanium modules
-
The UI module is responsible for native user-interface components and interaction among them
-
You can test all UI elements from Appcelerator KitchenSink app available at:
The goal of the UI module is to provide a native experience along with native performance by compiling
JavaScript code into their native counterparts
https://github.com/appcelerator/KitchenSink
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Module
-
The UI module is divided into 3 major areas:
‣
Views
‣
Windows
‣
Controls
-
UI objects are optimized not to be created into the native drawing context and placed into the device UI
surface until actually needed - i.e., they are drawn just when it is necessary and not as soon as you define
them
-
Titanium is optimized to also release memory once a view is no longer needed on-screen
Be careful with views defined in app.js because it is a global-scope file so objects defined in it are not
garbage-collected until the application exits
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI elements portability
-
Titanium components are designed to be portable across as many platforms as it supports
However, there are cases where a device does not support a specific feature or capability
-
-
For example:
•
Notifications are Android-only toast pop-up messages
•
Coverflow is an iOS-only presentation view
There are also cases where a device supports additional functionality
‣
Such capabilities are usually placed in a separate namespace, such as Titanium.UI.iPhone
‣
E.g., iOS natively supports animations when closing a window, so you can specify an available effect
such us the curl-up
window.close({transition: Titanium.UI.iPhone.AnimationStyle.CURL_UP});
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Views
-
Views are defined in Titanium.Proxy → Titanium.UI.View
-
Views can have their properties customized, such as their border’s color and radius
View is the base type for all UI widgets in Titanium
Views are containers that host visual elements, such as controls or other views, in a hierarchical structure
of children
Views can fire events, such as swipe or touch
Titanium provides a set of specialized views which are meant to perform both visual and interactive
functions, such as TableView or CoverflowView
‣
Specialized views are always named with the suffix View
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Events
-
Events are actions that can be detected by JavaScript
Such actions might be user-initiated, like taps or swipes, or system-initiated, like when an app is paused
Views can fire, listen and react to events
You specify which components in your app should listen for events with the addEventListener() method
var self = Ti.UI.createView({
backgroundColor :'#ffffff'
});
var v = Ti.UI.createView({
backgroundColor:'red',
width :'500',
height :'500'
});
self.add(v);
function eventOccurred (e) {
Ti.API.info('Event ' + e.type + ' occurred');
}
v.addEventListener('click', eventOccurred);
Alessandro Grazioli
Add a View to another View
addEventListener()‘s first parameter specifies the type of
event for which the View is listening.
The second parameter is a callback function executed whenever
the event is fired. Within it, an event object e is created. It has a
list of properties which depends on the event.
Event properties are listed on the API docs page for any given
module or component.
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Events
-
Common event types include click, swipe (a touch and drag action), scroll, dblclick and its synonym
doubletap, touchstart, touchmove, touchend
-
In addition to such common event types, some modules have their own special events
‣
The location services API includes events for heading and location changes
‣
The gestures module enables listening for the shake event
-
Common event properties include
‣
x and y which describe the (x, y) coordinates of the event in the view's coordinates (i.e. distance from
the top-left corner of the view which generated the event)
‣
type which is the name of the event type
‣
source which is a reference to the object on which the event was fired
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Event bubbling
UI events can bubble up (i.e.
propagate) from the view that was
actually touched through parent
views
var self = Ti.UI.createView({
backgroundColor :'#ffffff',
my_name : 'self'
});
var parent = Ti.UI.createView({
backgroundColor:'red',
width :'500',
height :'500',
my_name : 'parent'
});
var child= Ti.UI.createView({
backgroundColor:'red',
width :'250',
height :'250',
my_name : 'child'
});
This means that the event
propagates from the innermost
(the top view) to the outermost (the
container of all the other views)
element in the hierarchy
Running the example on the right
and clicking on child View, all
handlers functions are executed in
the order child - parent - self (i.e.,
from the innermost to the
outermost)
self.add(parent);
self.add(child);
The source is always the
innermost View
Alessandro Grazioli
function eventOccurredParent (e) {
Ti.API.info('Parent: event generated by ' + e.source.my_name);
}
function eventOccurredChild (e) {
Ti.API.info('Child: event generated by ' + e.source.my_name);
}
function eventOccurredSelf (e) {
Ti.API.info('Self: event generated by ' + e.source.my_name);
}
parent.addEventListener('click', eventOccurredParent);
child.addEventListener('click', eventOccurredChild);
self.addEventListener('click', eventOccurredSelf);
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Event bubbling
Events that represent user input are
bubbling events
The following events bubble: click,
dblclick, doubletap, longclick,
longpress, pinch, singletap, swipe,
touchcancel, touchend, touchmove,
touchstart, twofingertap
Other events, such as focus and
scroll, are view-specific. They
represent views reacting to user
input, and they do not bubble
The example on the right defines a
ScrollView and adds to it a
View and a TableView. You can
independently scroll the
TableView or the whole
ScrollView because
TableView’s scroll event do not
bubble to the ScrollView
Alessandro Grazioli
var self = Ti.UI.createView({
backgroundColor: '#ffffff'
});
var v = Ti.UI.createView({
backgroundColor: 'red',
width: '500',
height: '500'
});
var scrollView = Titanium.UI.createScrollView({
layout:'vertical'
});
scrollView.add(v);
var tableData = [];
for (var i = 0; i < 20; i++) {
var tableViewRow = Ti.UI.createTableViewRow({
selectionStyle:'none',
height:'7%'
});
var tableViewRowView = Ti.UI.createView({
width: "100%",
height: "100%",
backgroundColor: "transparent"
});
var tableViewRowViewLabel = Ti.UI.createLabel({
color: '#000',
font: { fontSize:18 },
text: 'Row number ' + i
});
tableViewRowView.add(tableViewRowViewLabel);
tableViewRow.add(tableViewRowView);
tableData.push(tableViewRow);
}
var table = Titanium.UI.createTableView({
data:tableData,
width:'80%',
height:'100%',
backgroundColor:'transparent'
});
scrollView.add(table);
self.add(scrollView);
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Event firing
-
To fire an event, use fireEvent() function which takes the name of the event to be fired as parameter
You can add, as a second parameter, a JSON-serializable list of data to be passed along with the event
You can set bubbling by using bubbles boolean property
view.fireEvent('event_name', { bubbles: false, custom_attribute: 'custom_value' });
-
For example, you might fire a custom event when a database is updated
‣
Any components that depend on the database – a table, for example – could listen for that event and update themselves
deleteButton.addEventListener('click', function(e) {
// Delete a record identified by a custom property of the event source
database.doDelete(e.whichRecord);
// Fire an event to inform that the database has just changed
theTable.fireEvent('db_updated');
});
theTable.addEventListener('db_updated', function(e) {
// Update data for a TableView
theTable.setData(database.getCurrentRecords());
});
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Event firing
-
Events can be local to a JS file or global to the app
‣
Events fired with view.fireEvent are only visible to elements defined in the JavaScript file where the
event gets fired
‣
App-level events, fired as Ti.App.fireEvent('event_name', {custom_attribute:
'value'}), are instead global
-
To listen to global events, use Ti.App.AddEventListener('event_name', handler)
Listeners to global events remain in scope the entire time your app is running
‣
Any local variable you reference within such listeners remains in memory while your app is running and this
can cause memory leaks (objects you do not need anymore are not garbage-collected)
‣
Remember to remove global events listeners when you do not need them anymore
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Event listener removal
-
You can remove an event listener thus preventing the associated component from reacting to such an event in the future
For example you may have a button that should only be active when one or more list items are checked
‣
When the user checks the first item, you can add the click event listener to the button
‣
If the user clears the last of the check marks, you can remove the event listener from the button.
-
To remove an event listener, you have to pass a reference to the handler to the function that was specified when you
added the event listener
‣
The easiest way to do this is to use a named function in the addEventListener() statement so you can also
pass that same function name to remove the listener
function handlerFunction(e) {
// Code executed by listeners when the event gets fired
}
view.addEventListener('event_name', handlerFunction});
view.removeEventListener('event_name', handlerFunction});
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Colors
-
Views have properties to control their color, such as backgroundColor and color
-
An additional alpha channel is supported as a prefix to the hex triplet (e.g., to make the orange-like color #FFAA00 semi-opaque, you
could use an alpha value of 55, giving, #55FFAA00 or #5FA0)
-
iOS also accepts colors specified in the form rgb(R,G,B) and rgba(R,G,B,A), with the color channels represented by integer numbers
between 0 and 255 and the alpha channel by a float number from 0 to 1.0 (transparent to opaque)
-
Alternatively, the following set of color names is recognized:
Colors may be specified as a hex triplet to determine the red, green and blue channels such as #000000, #FF0000, #00FF00,
#0000FF (a channel may be abbreviated when its two hex digits are identical, such as #F00, #0F0, #00F)
'transparent', 'aqua', 'black', 'blue', 'brown', 'cyan', 'darkgray', 'fuchsia', 'gray', 'green',
'lightgray', 'lime', 'magenta', 'maroon', 'navy', 'olive', 'orange', 'pink', 'purple', 'red', 'silver',
'teal', 'white', 'yellow'
-
On Android, if you want to create a semi-transparent window, set the opacity property before opening the window
If a color property is undefined, the default color of the particular UI element is applied
var view = Ti.UI.createView({
backgroundColor : rgba(255, 255, 255, 0.8),
color : 'black'
});
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI units & coordinates
-
-
You can specify size and coordinates for a view as:
‣
a number with no unit (e.g., { width: 50 }) - in this case the unit is set as the default one for the system (pixels on
Android and dips on iOS, mobile web and Tizen)
‣
a string consisting of a percentage referring to the view’s parent size - e.g., { width: '50%' }
‣
a string consisting of a number followed by a unit specifier - e.g., { width: '50px' }
Supported units are:
Unit
Specifier
pixels
px
Note
On Android, one DIP corresponds to one pixel on a 160DPI display.
On iOS, one DIP corresponds to one pixel on a non-Retina display, which is 163DPI for iPhone/iPod
touch and 132DPI for the iPad. A DIP corresponds to 2 pixels of width or height on a Retina display
density-independent pixels
dip
inches
in
millimiters
mm
Android, iOS only
centimeters
cm
Android, iOS only
points
pt
Typographical points of 1/72 of an inch
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI units & coordinates
-
On Android and iOS, the default unit can be overriden on a per-application level by setting the
ti.ui.defaultunit property in tiapp.xml
-
For example, to use DIPs as the default on all platforms, set defaultunit property in ti.app
element to dip
<property name="ti.ui.defaultunit" type="string">dip</property>
-
If you set such a property you should always express sizes as numbers with no unit
On iOS, font sizes are always treated as typographical points (i.e., pt)
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI units & coordinates - best practice
-
You should use density-independent pixels (dip)
If you want to get the screen width and height, you should do the following
‣
set the ti.ui.defaultunit property to ti.app file
<property name="ti.ui.defaultunit" type="string">dip</property>
‣
use Ti.Platform.displayCaps object to get the width and height of your screen
‣
However by default Ti.Platform.displayCaps returns the screen caps in pixels for Android and in
dip for iOS
‣
So it is necessary to divide such values by the logical density factor only on Android to convert it
to dip
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI units & coordinates - best practice
-
If you do not perform the division, a View set as large as the whole screen may not look properly on Android
-
displayCaps returns 1080 px for the width and
1776 px for the Nexus’ height, but since we set the
default unit to dip, when setting the View size such
values are considered as dip
The image shows that, while an app is properly displayed on an iPhone 6, its size is 3 times bigger on a Nexus 5
since on that device 1 dip represents 3 pixels
‣
The View’s width is then set to 1776 dip, that is
5328 px, and its height is set to 1080 dip, that is
3240 px since 1 dip = 3 px
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI size and position
-
Views are positioned using the left, right, top, bottom and center properties, and sized using the width
and height properties
‣
-
-
center allows to position the center of a View with respect to the top-left corner of its parent
The height and width properties also accept special values:
‣
Titanium.UI.FILL specifies that the view should fill the parent in that dimension
‣
Titanium.UI.SIZE specifies that the view should adjust this size to fit its contents, such as a label's text or
a view's children
‣
The string 'auto' specifies that the view should choose either Titanium.UI.FILL or
Titanium.UI.SIZE based on the default behavior for the View type
Sizes and positions can also be specified as a percentage of the parent's size as previously shown (i.e.,
{ width: '50%' })
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI size and position
-
The following example defines a Window including a red View which includes a child green View
The center of the green View is positioned (x, y) pixels far from the top-left corner of parent’s View
To center the child, use coordinates (x, y) = (childwidth, childheight) (a)
To put the child in the top-left corner, use coordinates (x, y) = (childwidth / 2, childheight / 2) (b)
var self = Ti.UI.createView({
backgroundColor:'#ffffff'
});
var parent = Ti.UI.createView({
backgroundColor:'red',
width: 100,
height: 100
});
var child = Ti.UI.createView({
backgroundColor:'green',
width: 50,
height: 50,
center:{x:60, y:60}
});
parent.add(child);
self.add(parent);
Alessandro Grazioli
50
c
50
(a)
(b)
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI size and position
-
Size and position properties are interpreted depending on the value of the view's layout property
Such a property specifies how the view positions its children and assumes a value of:
‣
'composite' or 'absolute': a child view is positioned based on its positioning properties (top, bottom,
left, right and center) - if no positioning properties are specified, the child is centered
‣
'vertical': children are laid out vertically from top to bottom.
‣
•
The first child is laid out top units from its parent's bounding box and each subsequent child is laid out below
the previous one.
•
The space between children is equal to the upper child's bottom value plus the lower child's top value
'horizontal': the children are laid out horizontally from left to right in rows.
•
If a child requires more horizontal space than exists in the current row, it is wrapped to a new row
•
The height of each row is equal to the maximum height of the children in that row
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI size and position
-
Two read-only dictionaries useful to get size and position information on a drawn View are:
‣
size: it has x, y, width and height properties and provides the rendered size and position of the view
‣
rect: has x, y, width and height properties and provides the rendered size and position of the bounding box of the
view
-
Both are only available after the View has been fully drawn, so if you want to use them, you need to set a listener for
postlayout event, which is fired at the end of a layout cycle
var self = Ti.UI.createView({
backgroundColor: '#ffffff'
});
var v = Ti.UI.createView({
backgroundColor: 'red',
width : '100',
height : '100'
});
self.add(v);
function printRect(e) {
Ti.API.info(v.rect.x + ', ' + v.rect.y);
}
self.addEventListener('postlayout', printRect);
Alessandro Grazioli
Trying to print rect properties before
View v has been drawn will return (0, 0)
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI size and position
-
-
Mobile OS include an accessibility service to aid impaired people
View provides 4 accessibility-related properties
‣
accessibilityLabel: a label identifying the view for the device's accessibility service
‣
accessibilityValue: a string describing the value (if any) of the view for the device's accessibility service
‣
accessibilityHint: briefly describes what performing an action (such as a click) on the view will do
‣
accessibilityHidden: whether the view should be ignored by the accessibility service
The first 3 represent text that the accessibility service (such as TalkBack on Android and VoiceOver on iOS)
reads to the user
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Window
-
Windows are top-level visual constructs that are the main part of the app’s UI (an app always has at least one window)
A Window can
‣
take different shapes and sizes
‣
have display and interaction properties such as fullscreen or modal
‣
be customized, such as changing its opacity or background color
-
Windows themselves are Views and also inherit View’s properties, functions and events
var newWin = Titanium.UI.createWindow({
backgroundColor : '#FFF'
});
newWin.open();
-
open method takes as optional parameter an opening animation
‣
You can use transform methods provided by Ti.UI.create2DMatrix() to define different animations such as scale
or rotate
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
Opening and closing with scale animation
function FirstWindow() {
var self = Ti.UI.createWindow({
backgroundColor: '#FFF'
});
-
The opening animation is set to scale from 0% to
100% of second window’s size (param 0 of
FirstWindow’s create2DMatrix method)
-
In SecondWindow’s createWindow method, the
scaling is set to 0 so that the animation can occur
var b = Ti.UI.createButton({
title: 'Close',
backgroundColor: '#EEE',
width: 100,
height: 50,
top: 100
});
ui/common/FirstWindow.js file
Since the opening animation defined by
FirstWindow is a scaling from 0 to 1, the
initial scale value of the Window is set to 0
b.addEventListener('click', function() {
var duration = 300;
var animateIn = Ti.UI.createAnimation({
transform: Ti.UI.create2DMatrix.scale(1),
duration: duration
});
Specify a scaling to 100% animation
function SecondWindow() {
var self = Ti.UI.createWindow({
backgroundColor: '#FFF',
transform: Ti.UI.create2DMatrix.scale(0)
});
var Window = require('ui/common/SecondWindow');
new Window().open(animateIn);
});
return self;
}
self.add(b);
Specify the opening animation
ui/common/SecondWindow.js file
module.exports = SecondWindow;
return self;
}
module.exports = FirstWindow;
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Window
-
Window objects can also be opened without referring to a CommonJS
module with the url property pointing to the JS file with the Window’s
structure
var w = Ti.UI.currentWindow;
var v = Ti.UI.createView({
backgroundColor : 'white',
width : '100%',
height : '100%',
layout : 'vertical'
});
var newWin = Titanium.UI.createWindow({
url: 'ui/common/new_win.js'
});
newWin.open();
-
-
Such Window object runs in a separate JavaScript context and thread
var b1 = Ti.UI.createButton({
title : 'Click Me',
backgroundColor : '#EEE',
width : 100,
height : 50,
top : 20
});
‣
This provides a way to decompose your application into smaller units
‣
When the window is closed, resources allocated in the window's context
gets cleaned up, saving memory and CPU cycles
b1.addEventListener('click', function() {
Ti.API.info('Clicked button');
});
When you DON'T use the url argument you have a single-context
application (variables are available globally as long as they are in scope different windows defined in the same file can access file-global variables)
var b2 = Ti.UI.createButton({
title : 'Close',
backgroundColor : '#EEE',
width : 100,
height : 50,
top : 2
});
When you DO use the url argument you have a multi-context application variables are only available within their own context (i.e., window), and
passing data between windows must be done via custom events or a
shared resource such as a database or app properties
Alessandro Grazioli
b2.addEventListener('click', function() {
w.close();
});
v.add(b1);
v.add(b2);
w.add(v);
new_win.js file
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Animations
-
Views can be animated by using the Animation object
Animations can be set to reverse themselves automatically on completion, and to repeat a given number of times
Multiple animations can be combined in sequence, starting the following when the previous completes
Use the Titanium.UI.createAnimation method to create an animation object
iOS supports both 2D and 3D matrix transformations in animations and
you can also specify an animation curve (or easing) function to control
the pace of the animation by setting the animation's curve property
to one of the ANIMATION_CURVE constants defined in Titanium.UI.
‣
-
E.g., ANIMATION_CURVE_EASE_IN specifies an animation
that starts slowly and then speeds up
iOS also supports transitions between windows or views
Android supports 2D matrix transformations
The example defines a 2D matrix that rotates translates and scales both
horizontally and vertically a View in2 seconds. The View’s opacity is also
reduced to 60% during the animation.
Alessandro Grazioli
var box = Ti.UI.createView({
backgroundColor : 'red',
height : '100',
width : '100'
});
win.add(box);
box.addEventListener('click', function() {
var matrix = Ti.UI.create2DMatrix()
matrix = matrix.rotate(180).translate(10,10).scale(2, 2);
var a = Ti.UI.createAnimation({
transform : matrix,
duration : 2000,
opacity : 0.6,
autoreverse : true,
repeat : 3
});
box.animate(a);
});
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
CommonJS modules
-
The recommended way to define a Window is by using CommonJS syntax
-
The file in which the new Window is defined, is a CommonJS module
CommonJS is a project whose goal is the definition of an ecosystem for
JavaScript outside of the browser (that is, defining specifics that desktop or
server-side programs should follow)
‣
It includes the constructor function, having the same name of the file, that
has to be invoked to create the Window
‣
The constructor includes the definition of the Window, of its elements and of
their behavior, and returns the Window itself
‣
‣
After the constructor, CommonJS module.exports special variable is
used to make the constructor public to the app
Use the constructor anywhere by invoking CommonJS require() method,
and open a Window using CommonJS open() method
var MyNewWindow = require('ui/common/NewWindow');
new MyNewWindow().open();
Alessandro Grazioli
// Window Component Constructor
function NewWindow() {
// Create component instance
var self = Ti.UI.createWindow({
backgroundColor:'#fff'
});
var view = Ti.UI.createView({
backgroundColor:'#0F0'
});
self.add(view);
}
return self;
// Make constructor function public
module.exports = NewWindow;
ui/common/NewWindow.js file
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
CommonJS modules
-
You can use use CommonJS modules to define any kind of View and refer to it from anywhere in your app by
invoking CommonJS require() method
-
The example is an extension to the previous one, where the content of self Window is loaded from MyViews.js file
function NewWindow() {
var self = Ti.UI.createWindow({
backgroundColor: '#ffffff'
});
function Views() {
var self = Ti.UI.createView();
var label = Ti.UI.createLabel({
color: '#000000',
text: 'Title',
height:'auto',
width:'auto'
});
var Views = require('ui/common/Views');
var selfViews = new Views();
self.add(selfViews);
self.add(label);
return self;
}
ui/common/NewWindow.js file
label.addEventListener('click', function(e) {
alert(e.source.text);
});
module.exports = NewWindow;
return self;
ui/common/Views.js file
}
module.exports = Views;
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
Passing data among Windows
-
You can pass context (data) among Windows by
using a CommonJS module which provides variables
and objects that can be initialized and retrieved
-
The example is a module which provides an object, a
variable and getter/setter methods
-
The first window of the project loads the module and
uses the setter methods to store some data before
opening the second window
-
The second window loads the same module and is
able to retrieve the content saved by the first one
with the getter methods
Alessandro Grazioli
var dataObject = {};
var dataVariable;
ui/common/PassData.js file
function setDataObject (obj) {
dataObject = obj;
}
function getDataObject () {
return dataObject;
}
function setDataVariable (variable) {
dataVariable = variable;
}
function getDataVariable () {
return dataVariable;
}
exports.setDataObject =
exports.getDataObject =
exports.setDataVariable
exports.getDataVariable
setDataObject;
getDataObject;
= setDataVariable;
= getDataVariable;
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
Passing data among Windows - sliding animation
function FirstWindow() {
var self = Ti.UI.createWindow({
backgroundColor: '#FFF'
});
var animationIn = {};
var animationOut;
-
FirstWindow defines an opening and closing animation for
SecondWindow and stores them in PassData module
function setAnimationIn (obj) {
animationIn = obj;
}
var b = Ti.UI.createButton({
function getAnimationIn () {
title: 'Close',
return animationIn;
backgroundColor: '#EEE',
}
width: 100,
function setAnimationOut (obj) {
height: 50,
animationOut = obj;
top: 100
}
});
function getAnimationOut () {
b.addEventListener('click', function() {
return animationOut;
var duration = 300;
}
var animateIn = Ti.UI.createAnimation({
exports.setAnimationIn = setAnimationIn;
left: 0,
exports.getAnimationIn = getAnimationIn;
duration: duration
exports.setAnimationOut = setAnimationOut;
});
var animateOut = Ti.UI.createAnimation({
exports.getAnimationOut = getAnimationOut;
left: 0,
-
SecondWindow retrieves the closing animation from
PassData module and uses it
function SecondWindow() {
var self = Ti.UI.createWindow({
backgroundColor: ‘#FFF',
left: Titanium.Platform.displayCaps.platformWidth
});
var passModule = require('ui/common/PassData');
var b = Ti.UI.createButton({
title : 'Close',
Since the opening animation defined by
backgroundColor : '#EEE',
FirstWindow is a sliding from current
width : 100,
left to 0, the initial left value of the
height : 50,
Window is set to the screen size, thus the
top : 100
Window is placed outside of the viewport
});
ui/common/PassData.js file
duration: duration
});
var passModule = require('ui/common/PassData');
passModule.setAnimationIn(animateIn);
passModule.setAnimationOut(animateOut);
var Window = require('ui/common/SecondWindow');
new Window().open(passModule.getAnimationIn());
});
Specify a sliding
animation
b.addEventListener('click', function() {
self.close(passModule.getAnimationOut());
});
self.add(b);
self.add(b);
return self;
Specify opening animation
}
module.exports = FirstWindow;
Alessandro Grazioli
Retrieve closing animation
ui/common/FirstWindow.js file
return self;
ui/common/SecondWindow.js file
}
module.exports = SecondWindow;
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Specialized Windows
-
Titanium provides some specialized views that manage other windows:
‣
NavigationWindow (iOS only)
‣
‣
‣
SplitWindow (iOS only)
TabGroup
Tab
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI NavigationWindow (iOS only)
NavigationWindow is defined in Titanium.Proxy →
Titanium.UI.View → Titanium.UI.Window →
Titanium.UI.iOS.NavigationWindow
function NavigationWindow() {
var win2 = Titanium.UI.createWindow({
backgroundColor: 'red',
title: 'Red Window'
});
var win1 = Titanium.UI.iOS.createNavigationWindow({
window: win2
});
NavigationWindow is a native iOS view that manages the navigation
of hierarchical content from a first Window (root) to other Windows
var win3 = Titanium.UI.createWindow({
backgroundColor : 'blue',
title : 'Blue Window'
});
var button = Titanium.UI.createButton({
title: 'Open Blue Window'
});
A bar is displayed on top, with a link to return to the previous Window
in the hierarchy
One more windows is defined, win3
button.addEventListener('click', function() {
win1.openWindow(win3, {
animated: true
win2 contains
});
when clicked,
});
In the example’s CommonJS module, win2 is the root Window (the
first one displayed) - it has to be defined before the
NavigationWindow, so that it can be set as its window property
win2.add(button);
a button that,
opens win3
inside the NavigationWindow
with a standard animation
var button2 = Titanium.UI.createButton({
title: 'Close Blue Window'
});
button2.addEventListener('click', function() {
win1.closeWindow(win3, {
animated: true
});
});
win1 and win3 presents respectively an open and a close button
Opening and closing of windows are performed by
NavigationWindow
NavigationWindow’s
content is win2
win3.add(button2);
}
return win1;
module.exports = NavigationWindow;
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI SplitWindow (iPad only)
SplitWindow is defined in Titanium.Proxy → Titanium.UI.View
→ Titanium.UI.Window → Titanium.UI.iPad.SplitWindow
function SplitWindow() {
var detail = Ti.UI.createWindow({
backgroundColor: 'white'
});
var label1 = Ti.UI.createLabel({
text: 'Detail View'
});
detail.add(label1);
SplitWindow is a native iOS view, only for the iPad, that manages
manages the presentation of two side-by-side view controllers
var detailNav = Ti.UI.iOS.createNavigationWindow({
window: detail
});
var master = Ti.UI.createWindow({
backgroundColor: 'gray'
});
var label2 = Ti.UI.createLabel({
text: 'Master View'
});
master.add(label2);
You use this class to implement a master-detail interface, in which the leftside view presents a list of items and the right-side presents details of the
selected item
The master view is also a
NavigationWindow
whose content is a normal
Window
var masterNav = Ti.UI.iOS.createNavigationWindow({
window: master
});
By default, the SplitWindow shows both master and detail views in
landscape orientation
var splitWin = Ti.UI.iPad.createSplitWindow({
detailView: detailNav,
Setting master and detail
masterView: masterNav
});
the SplitWindow
When the device switches into portrait orientation, the detail view occupies
the entire screen and the user can click a button to bring up the master view
as a floating view (to show the master view in both orientations, set
showMasterInPortrait property to true)
In the example’s CommonJS module, the detail View is a
NavigationWindow so that you can present a hierarchy of Windows
The detail view is a
NavigationWindow
whose content is a normal
Window
for
splitWin.addEventListener('visible', function(e) {
if (e.view == 'detail') {
e.button.title = "Master";
detail.leftNavButton = e.button;
} else if (e.view == 'master') {
detail.leftNavButton = null;
}
});
return splitWin;
}
module.exports = SplitWindow;
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Tab & TabGroup
-
Tab is defined in Titanium.Proxy → Titanium.UI.View → Titanium.UI.Tab
-
The behavior of Tabs and TabGroups follows the platform's native navigation style, which varies significantly between
platforms
Tabs are instances for a TabGroup - each Tab represents a window (or a hierarchy of windows starting from a root) inside
the group
‣
On iOS, a Tab maintains a stack of windows. Calling open opens a new window on top of the stack. When a window is
closed, it is removed from the stack making the previous window visible - the root tab window cannot be removed
‣
On Android, a Tab does not maintain a stack of open windows,
so if you press the Back button on your device, the whole
TabGroup is removed from the stack of Activities and the
system presents you the Activity that was just under the
TabGroup in the stack
-
The example presents a CommonJS module representing a Tab
‣
You have to define the root window in the Tab (tabWindow) and the
Tab itself (tab) specifying the root window as its window property
Alessandro Grazioli
var tabWindow = Titanium.UI.createWindow({
title: 'Window 1 Title',
backgroundColor: 'white'
});
var tab = Titanium.UI.createTab({
window: tabWindow,
title: 'Tab 1'
});
return tabWindow;
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Tab & TabGroup
function MyTabGroup() {
var self = Ti.UI.createTabGroup();
TabGroup is defined in Titanium.Proxy → Titanium.UI.View
→ Titanium.UI.Window
var TabContent1 = require('ui/common/Win1');
var TabContent2 = require('ui/common/Win2');
A TabGroup can be defined to create a window with a number of
Tabs, each referred to from a button in a bar displayed under the tabs
window in iOS, and on top of the tabs window in Android
var win1 = new TabContent1(self);
var win2 = new TabContent2();
1. Specify the modules containing the window code for each tab
var tab1 = Ti.UI.createTab({
title: 'Tab 1',
window: win1
});
var tab2 = Ti.UI.createTab({
title: 'Tab 2',
window: win2
});
2. Create the Windows from the code required at previous step by
calling constructors specified in the files
self.addTab(tab1);
self.addTab(tab2);
3. Create the tabs and specify their root window
4. Add the tabs to the TabGroup
};
return self;
If you want Tabs to interact with the TabGroup - for example to add
to a Tab a button that closes the group - you have to pass to the
Tab’s constructor a reference to the TabGroup (container in Win1
is a reference to self)
Alessandro Grazioli
module.exports = MyTabGroup;
function Win1(container) {
var self = Ti.UI.createWindow();
return self;
};
module.exports = Win1;
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Controls
-
Controls or Widgets are visual elements such as sliders, buttons and switches
They provide a visual element which has a defined behavior and special configuration and events
Controls are Views and therefore inherit View’s properties, functions and events
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Controls - Switch
-
A Switch is an on/off controller defined in Titanium.Proxy → Titanium.UI.View →
Titanium.UI.Switch
-
On Android, a switch can have text associated with it (add attributes titleOn and/or titleOff), and
appears as either a toggle button or a checkbox (add attribute
style:Ti.UI.Android.SWITCH_STYLE_CHECKBOX)
-
On iOS, the switch appears as an iOS on/off switch and doesn't have any text associated with it
-
The example adds a switch to a Window and
sets a change event listener for it
var self = Ti.UI.createView({
backgroundColor: '#ffffff'
});
The value property must be specified in the
definition for iOS compatibility
var switchButton = Ti.UI.createSwitch({
value: true
});
The change event gets fired each time the user
taps the switch
switchButton.addEventListener('change',function(e) {
alert('Switch value: ' + switchButton.value);
});
self.add(switchButton);
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Controls - Slider
-
A Slider is a component with a draggable thumb defined in Titanium.Proxy →
Titanium.UI.View → Titanium.UI.Slider
-
A slider lets the user select from a range of values by dragging the slider thumb (e.g. the volume level
selector in music players is implemented as a slider) var win = Ti.UI.createWindow({
backgroundColor: 'white'
-
On Android, both min and max values must be
specified for the slider to work properly
-
The example adds a slider and a label to a
Window and sets a change event listener for
the slider
‣
The text of the label is set to the slider value
each time the user drags the thumb, in the
format 3 integer and 1 decimal digits (%3.1f)
Alessandro Grazioli
});
var slider = Titanium.UI.createSlider({
top: 50,
min: 0,
max: 100,
width: '100%',
value: 50
});
var label = Ti.UI.createLabel({
text: slider.value,
width: '100%',
height: 'auto',
top: 30,
left: 0,
textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER
});
slider.addEventListener('change', function(e) {
label.text = String.format("%3.1f", e.value);
});
win.add(slider);
win.add(sliderLabel);
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Controls - Button
-
A Button is defined in Titanium.Proxy → Titanium.UI.View → Titanium.UI.Button
It has 4 states:
‣
‣
disabled
‣
focused (only used on Android devices that
have navigation keys or a keyboard, to indicate
which button has input focus)
‣
-
normal
selected (being pressed)
var button = Titanium.UI.createButton({
title: 'Button Text',
top: 10,
width: 100,
height: 50
});
button.addEventListener('click',function(e) {
Titanium.API.info("You clicked the button");
});
The example presents the definition of a button
and the associated listener for the click event
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Controls - Button
-
You can specify background images and text for each state
While Android provides default images for the 4 states, iOS does not
iOS provides the style special property which can be set to one of the values defined in
Titanium.UI.iPhone.SystemButtonStyle
‣
PLAIN: default style
‣
BORDERED: like plain but with a thick border
‣
BAR: if you do not use style property and do not provide a custom background image, the button will have a
transparent background
-
iOS also provides systemButton special property which lets you create a predefined system-defined button, such as
the Camera or Add buttons - it just sets the look, not the behavior (i.e. a Camera button does not open the Camera
app, but it behaves just according to what the developer set)
var cancelButton = Ti.UI.createButton({systemButton: Ti.UI.iPhone.SystemButton.CANCEL});
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Controls - ButtonBar (iOS only)
-
A ButtonBar is a native iOS controller View defined in Titanium.Proxy → Titanium.UI.View →
Titanium.UI.ButtonBar
-
The ButtonBar is a set of buttons joined into a single control
Each button can have a text label or an icon, but not both
TabbedBar is a specialized ButtonBar where the last selected button maintains a pressed or selected state
The buttons share a common style, defined by the style property that can be set to one of the constants defined in
Titanium.UI.iPhone.SystemButtonStyle (PLAIN, BORDERED, BAR)
-
If you want the background color, or background
gradient, of the button bar to show through, the style
must be set to BAR (buttons with translucent background)
-
The example presents the definition of a ButtonBar
and the associated listener for the click event
‣
Buttons are identified by their label so the event handler
uses e.source.label to recognize the clicked button
var bb = Titanium.UI.createButtonBar({
labels:['One', 'Two', 'Three'],
backgroundColor: '#336699',
top: 50,
style: Titanium.UI.iPhone.SystemButtonStyle.BAR,
height: 25, width:200
});
bb.addEventListener('click', function(e) {
Ti.API.info('Clicked ' + e.source.label);
});
win.add(bb);
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Forms
-
Forms allow the user to provide input to the application
Titanium provides a number of specialized Views to
this purpose
-
TextField
SearchBar
TextArea
Picker
EmailDialog
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Forms - TextField
-
A TextField is a single-line text field defined in Titanium.Proxy → Titanium.UI.View →
Titanium.UI.TextField
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
The example on the right presents a basic TextField
with rounded corners
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
var send = Titanium.UI.createButton({
title: 'Send',
style: Titanium.UI.iPhone.SystemButtonStyle.DONE
});
var camera = Titanium.UI.createButton({
title: 'Camera',
style: Titanium.UI.iPhone.SystemButtonStyle.DONE
});
var cancel = Titanium.UI.createButton({
title: 'Send',
style: Titanium.UI.iPhone.SystemButtonStyle.DONE
});
var textField = Titanium.UI.createTextField({
borderStyle : Titanium.UI.INPUT_BORDERSTYLE_BEZEL,
hintText: 'Focus to see keyboard with toolbar',
keyboardToolbar : [cancel, camera, send],
keyboardToolbarColor: '#999',
keyboardToolbarHeight: 40,
top: 10,
width: 300,
height: 35
});
win.add(textField);
Alessandro Grazioli
var textField = Ti.UI.createTextField({
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED,
top: 10, left: 10,
width: 250, height: 60
});
win.add(textField);
-
On iOS, a configurable toolbar can be displayed above
the virtual keyboard
-
The example on the left
defines a TextField
and a custom toolbar
with 3 buttons
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Forms - SearchBar
-
A SearchBar is a specialized text field for entering search text defined in Titanium.Proxy →
Titanium.UI.View → Titanium.UI.SearchBar
-
The SearchBar object is closely modeled on the iOS native search bar therefore not all features are
supported on other platforms
var search = Titanium.UI.createSearchBar({
showCancel: true,
eight: 43,
value: 'Enter a string'
});
search.addEventListener('return', function(e) {
Ti.API.Info('Inserted value is: ' + e.source.value);
});
search.addEventListener('focus', function(e) {
search.value = '';
});
win.add(search);
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Forms - TextArea
-
A TextArea is a multiline text field that supports editing and scrolling defined in Titanium.Proxy →
Titanium.UI.View → Titanium.UI.TextArea
-
The example on the right presents a customized TextArea (returnKeyType specifies the text to display on the
keyboard Return key when the text area is focused)
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
var textArea = Ti.UI.createTextArea({
borderWidth: 2,
borderColor: '#BBB',
borderRadius: 5,
color: '#888',
font: {fontSize: 20, fontWeight: 'bold'},
keyboardType: Ti.UI.KEYBOARD_NUMBER_PAD,
returnKeyType: Ti.UI.RETURNKEY_GO,
textAlign: 'left',
value: 'I am a textarea',
top: 60,
width: 300,
height : 70
});
win.add(textArea);
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
var send = Titanium.UI.createButton({
title: 'Send',
style: Titanium.UI.iPhone.SystemButtonStyle.DONE
});
var camera = Titanium.UI.createButton({
title: 'Camera',
style: Titanium.UI.iPhone.SystemButtonStyle.DONE
});
var cancel = Titanium.UI.createButton({
title: 'Send',
style: Titanium.UI.iPhone.SystemButtonStyle.DONE
});
var textArea = Ti.UI.createTextArea({
borderColor : '#000',
color : '#000',
keyboardToolbar : [cancel, camera, send],
keyboardToolbarColor : '#999',
keyboardToolbarHeight : 40,
value : 'Focus to see keyboard with toolbar',
top : 10, width : 300, height : 120
});
win.add(textArea);
Alessandro Grazioli
-
As for the TextField, on iOS a configurable toolbar
can be displayed above the virtual keyboard
-
The example on the left defines a TextField and
a custom toolbar with 3 buttons
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Forms - Picker
-
If you want to use a single-column Picker, define an array of PickerRow elements and use the add method to add it
to the Picker (left-side example)
-
If you want to use a multi-column Picker, define an array of N PickerColumn elements, M arrays of PickerRow
elements, add each array of PickerRows to a PickerColumn and add the array of
PickerColumn to the Picker (right-side example)
setSelectedRow takes as
var win = Ti.UI.createWindow({
parameters the row and column of
backgroundColor : 'white'
the selected item. The 3rd param is
});
var picker = Ti.UI.createPicker({
a boolean specifying if the selection
top : 50
should be animated.
});
var data = [];
data[0]=Ti.UI.createPickerRow({title:'Bananas'});
data[1]=Ti.UI.createPickerRow({title:'Strawberries'});
data[2]=Ti.UI.createPickerRow({title:'Mangos'});
data[3]=Ti.UI.createPickerRow({title:'Grapes'});
var win = Ti.UI.createWindow({
backgroundColor : 'white'
});
var picker = Ti.UI.createPicker({
top : 50,
useSpinner : true
});
picker.selectionIndicator = true;
var fruit = [ 'Bananas', 'Strawberries', 'Mangos', 'Grapes' ];
var color = [ 'red', 'green', 'blue', 'orange' ];
var column1 = Ti.UI.createPickerColumn();
for(var i = 0, ilen = fruit.length; i < ilen; i++){
var row = Ti.UI.createPickerRow({ title: fruit[i] });
column1.addRow(row);
}
var column2 = Ti.UI.createPickerColumn();
for(var i = 0, ilen=color.length; i < ilen; i++){
var row = Ti.UI.createPickerRow({ title: color[i] });
column2.addRow(row);
}
picker.add([column1,column2]);
win.add(picker);
win.open();
picker.add(data);
picker.selectionIndicator = true;
win.add(picker);
win.open();
// Must after picker has been displayed
picker.setSelectedRow(0, 2, false); // select Mangos
Alessandro Grazioli
// Must be after picker has been displayed
picker.setSelectedRow(0, 2, false); // select Mangos
picker.setSelectedRow(1, 3, false); // select Orange
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI Forms - EmailDialog
-
An EmailDialog is a modal window that allows users to compose and send an email and is defined in
Titanium.Proxy → Titanium.UI.EmailDialog
-
The example presents the definition of an email dialog with a listener for the complete event which gets fired when the
dialog has completed sending an e-mail
function buttonListenerHandler(e) {
-
var emailDialog = Ti.UI.createEmailDialog();
emailDialog.subject = "Hello";
emailDialog.toRecipients = ['[email protected]'];
emailDialog.messageBody = '<b>This is the body</b>';
var f = Ti.Filesystem.getFile('file.wav');
emailDialog.addAttachment(f);
emailDialog.open();
The code also adds an attachement file
emailDialog.addEventListener('complete', function(e) {
alert('e-mail sent');
});
}
var button = Ti.UI.createButton({
title: 'Send e-mail',
backgroundColor: '#EEE',
width: 200,
height: 50,
top: 30
});
button.addEventListener('click', button5ListenerHandler);
win.add(button);
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI TableView
-
A TableView is used to present information, organized in sections and rows, in a vertically-scrolling view and is defined in
Titanium.Proxy → Titanium.UI.View → Titanium.UI.TableView
-
A TableView object is a container for TableViewSection objects that are, in turn, containers for TableViewRow objects
You can add a SearchBar to look for elements
‣
-
var win = Ti.UI.createWindow();
The considered property is specified by filterAttribute
var searchBar = Titanium.UI.createSearchBar({
barColor: '#000',
showCancel: false
});
There are 3 approaches to the creation of a TableView
1. The simplest approach:
var tableData = [
{title : 'Apples'},
{title : 'Bananas'},
{title : 'Carrots'},
{title : 'Potatoes'}
];
•
•
create an array of JSON-serialized properties for
TableViewRow properties, such as title,
backgroundColor, color, …
the rows are implicitly created, added to a single
TableViewSection, and then added to the
TableView as presented on the right
var table = Ti.UI.createTableView({
search: searchBar,
data: tableData,
filterAttribute: 'title'
});
win.add(table);
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
UI TableView
Distributed Systems Group
function MyTableView() {
var win = Ti.UI.createWindow({
backgroundColor : 'white'
});
// generate random number, used to make each row appear distinct
function randomInt(max) {
return Math.floor(Math.random() * max) + 1;
}
2. The second approach is to explicitly create
TableViewRow objects
var defaultFontSize = Ti.Platform.name === 'android' ? 16 : 14;
var tableData = [];
•
Such an approach provides more control over
the layout of the rows since you can add child
views (e.g., labels, images, buttons, …)
for (var i = 1; i <= 20; i++) {
var row = Ti.UI.createTableViewRow({
selectedBackgroundColor: 'white',
rowIndex: i, // custom property to determine the row during events
height: 60
});
•
When passed to the TableView, a single
TableViewSection is automatically created
•
The TableViewRow has a custom property
named rowIndex which can be used to
identify the clicked row in a listener for click
event as e.source.rowIndex
var imageAvatar = Ti.UI.createImageView({
image: 'images/user.png',
left: 10,
top: 5,
width: 50,
height: 50
});
row.add(imageAvatar);
var labelUserName = Ti.UI.createLabel({
color: '#576996',
font: {
fontFamily : 'Arial',
fontSize : defaultFontSize + 6,
fontWeight : 'bold'
},
text: 'Name Surname ' + i,
left: 70,
top: 6,
width : 200,
height : 30
});
row.add(labelUserName);
tableData.push(row);
}
var tableView = Ti.UI.createTableView({
backgroundColor : 'white',
data : tableData
});
win.add(tableView);
return win;
}
module.exports = MyTableView;
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
UI TableView
Distributed Systems Group
function MyTableView() {
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
var sectionFruit = Ti.UI.createTableViewSection({
headerTitle: 'Fruit'
});
3. The third approach is to explicitly create sets of
TableViewRow and add them to their own
TableViewSection objects, which are then
added to a TableView, to enable the rows to
be organized
sectionFruit.add(Ti.UI.createTableViewRow({
title: 'Apples',
foodType : 'fruit'
}));
sectionFruit.add(Ti.UI.createTableViewRow({
title: 'Bananas',
foodType : 'fruit'
}));
•
var sectionVeg = Ti.UI.createTableViewSection({
headerTitle: 'Vegetables'
});
Headers or footers titles must be configured
in order for the sections to be visible
sectionVeg.add(Ti.UI.createTableViewRow({
title: 'Carrots',
foodType : 'vegetable'
}));
sectionVeg.add(Ti.UI.createTableViewRow({
title: 'Potatoes',
foodType : 'vegetable'
}));
var table = Ti.UI.createTableView({
data: [sectionFruit, sectionVeg]
});
table.addEventListener('click', function(e){
alert(e.source.title + ' are of type ' + e.source.foodType);
});
win.add(table);
return win;
}
module.exports = MyTableView;
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI TableView search filtering
-
As previously described, you can add a SearchBar to look
for items in a TableView
-
SearchBar compares the inserted text with
filterAttribute property values of each
TableViewRow
-
-
var viewContainingTableView = Titanium.UI.createView({
width:'100%', height:'100%', top:0, left:0, layout:'vertical'
});
var table = Ti.UI.createTableView({
filterAttribute: 'title',
The width of
data: [sectionFruit, sectionVeg]
each button is
});
set as the width
// Labels for the buttons bar
of the screen
var buttonObjects = [ {‘Title'}, {'Food type’} ];
If you want to allow filtering different parameters, you need to
provide a way for the user to choose the parameter and
subsequently modify the TableView’s filterAttribute
‣
E.g., if your app includes a list of customers, each having a
name and an address, you can add 2 buttons that specify
the parameter the user wants to look for
‣
When the user taps a button, the associated property is set
as filterAttribute
The examples defines a View including 2 buttons that allow
specifying if the SearchBar has to look the title or the
foodType attribute of each TableViewRow
Alessandro Grazioli
divided by the
number of
buttons. The
buttons’ width is
set accordingly
var searchBb = Titanium.UI.createView({
top: 0, left: 0, height: 35, width:'100%',
index: 0 // Default to first button selected
});
for (var i = 0; i < buttonObjects.length; i++) {
var button = Ti.UI.createButton({
top : 0,
title : buttonObjects[i],
width :
Math.floor(Titanium.Platform.displayCaps.platformWidth /
buttonObjects.length),
left : i * (Titanium.Platform.displayCaps.platformWidth /
buttonObjects.length),
index : i // The index is used to detect the pressed button
});
button.addEventListener('click', function(e) {
if(e.source.index == 0) table.filterAttribute = 'title';
else if(e.source.index == 1) table.filterAttribute = 'foodType';
});
searchBarButtons.add(button);
}
viewContainingTableView.add(searchBb);
viewContainingTableView.add(table);
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI ListView
-
-
A ListView is an alternative to TableView to present information organized in sections and rows
in a vertically-scrolling view, and is defined in Titanium.Proxy → Titanium.UI.View →
Titanium.UI.ListView
‣
ListView corresponds to TableView
‣
ListSection corresponds to TableViewSection
‣
ListItem corresponds to TableViewRow
The difference is that ListView uses a data-oriented approach while TableView uses a vieworiented approach
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI ListView
-
ListView is designed for performance, but one side-effect is that you cannot directly manipulate the View (i.e., add
children, set view properties and bind event callbacks) as you can in a TableView
-
With TableView:
‣
you can directly add TableViewRow to a table using the data property
‣
you can directly create a TableViewRow and customize its styling by setting properties
‣
you can add view subcomponents to a TableViewRow by using the add method
-
With ListView:
‣
you need to explicitly create a ListSection to add a ListItem to a ListView (in a TableView, a
TableViewRow can be directly added to a TableView since a TableViewSection is implicitly created)
‣
you cannot add views to a ListItem using the add method - to do so, define an ItemTemplate object, which is
bound to a list data item using the template property
‣
You cannot explicitly bind events for a ListItem - to do so, use the events dictionary of ItemTemplate
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
-
Distributed Systems Group
UI ListView
The template (left) uses bindId values to set custom style for the elements
// A custom template that displays an image on the
// left and a title next to it with a subtitle below
var myTemplate = {
childTemplates : [{
type: 'Ti.UI.ImageView',
bindId: 'pic',
properties: {// Sets the ImageView properties
width: '50dp',
height: '50dp',
left: 0
}
}, {// Title
type: 'Ti.UI.Label',
bindId: 'info',
properties: {// Sets the Label properties
color: 'black',
font: {
fontFamily: 'Arial',
fontSize: '20dp',
fontWeight: 'bold'
},
left: '60dp',
top: 0,
}
}, {// Subtitle
type: 'Ti.UI.Label',
bindId: 'it_info',
properties: {// Sets the Label properties
color: 'gray',
font: {
fontFamily: 'Arial',
fontSize: '14dp'
},
left: '60dp',
top: '25dp'
}
}]
};
Alessandro Grazioli
function MyListView() {
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
var listView = Ti.UI.createListView({
templates: {
'template': myTemplate
},
defaultItemTemplate : 'template'
});
var sections = [];
var fruitSection = Ti.UI.createListSection({
headerTitle: 'Fruits / Frutta'
});
var fruitDataSet = [{
pic: {
image: 'apple.png'
},
info: {
text: 'Apple'
},
it_info: {
text: 'Mela'
}
}];
fruitSection.setItems(fruitDataSet);
sections.push(fruitSection);
var vegSection = Ti.UI.createListSection({
headerTitle: 'Vegetables / Verdure'
});
var vegDataSet = [{
pic: {
image: 'carrot.png'
},
info: {
text: 'Carrot'
},
it_info: {
text: 'Carota'
}
}];
vegSection.setItems(vegDataSet);
sections.push(vegSection);
var vegSection = Ti.UI.createListSection({
headerTitle: 'Vegetables / Verdure'
});
var vegDataSet = [{
pic: {
image: 'carrot.png'
},
info: {
text : 'Carrot'
},
it_info: {
text: 'Carota'
}
}];
vegSection.setItems(vegDataSet);
sections.push(vegSection);
var grainSection = Ti.UI.createListSection({
headerTitle: 'Grains / Grani'
});
var grainDataSet = [{
pic: {
image: 'corn.png'
},
info: {
text: 'Corn'
},
it_info: {
text: 'Mais'
}
}];
grainSection.setItems(grainDataSet);
sections.push(grainSection);
listView.setSections(sections);
win.add(listView);
return win;
}
module.exports = MyListView;
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI ImageView & Label
-
ImageView is a View which allows displaying an image
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
It is defined in Titanium.Proxy → Titanium.UI.View
→ Titanium.UI.ImageView
var image = Ti.UI.createImageView({
image: '/images/myimage.png'
});
win.add(image);
-
A Label allows the definition of a text label, with optional
background image
-
It is defined in Titanium.Proxy → Titanium.UI.View
→ Titanium.UI.Label
-
You can add Unicode 8-bit characters
You should store UI strings in i18n/LANGUAGE/strings.xml
and access them using L('STRING_NAME')
var label = Ti.UI.createLabel({
color: 'blue',
text: 'A label with\na few line breaks\nand
unicode (UTF8)\nsymbols such as\na white chess
piece \u2655\nand the euro symbol \u20ac\nlooks
like this!\n',
textAlign: Ti.UI.TEXT_ALIGNMENT_LEFT,
top: 30,
width: 300,
height: 200
});
win.add(label);
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
UI ScrollView
Distributed Systems Group
-
A ScrollView is a View that contains a horizontally
and/or vertically -scrollable region of content and is
defined in Titanium.Proxy →
Titanium.UI.View →
Titanium.UI.ScrollView
function MyScrollView() {
var self = Ti.UI.createView({
backgroundColor: '#ffffff’
});
var view = Ti.UI.createView({
backgroundColor: 'red',
width: '500',
height: '500'
});
var scrollView = Titanium.UI.createScrollView({
layout: 'vertical',
});
-
Views added to the ScrollView will be scrolled
based on their size - if they fit within the size of their
ScrollView, they will not scroll
-
The example creates a ScrollView including a View
followed by a TableView
scrollView.add(view);
var tableData = [];
for (var i = 0; i < 20; i++) {
var tableViewRow = Ti.UI.createTableViewRow({
selectionStyle : 'none',
height: '7%'
});
var tableViewRowView = Ti.UI.createView({
width: "100%",
height: "100%",
backgroundColor : "transparent",
});
var tableViewRowViewLabel = Ti.UI.createLabel({
color: '#000',
font: { fontSize : 18 },
text: 'Row number ' + i
});
tableViewRowView.add(tableViewRowViewLabel);
tableViewRow.add(tableViewRowView);
tableData.push(tableViewRow);
}
var table = Titanium.UI.createTableView({
data: tableData,
width: '80%',
height: '100%',
backgroundColor: 'transparent'
});
scrollView.add(table);
self.add(scrollView);
return self;
}
module.exports = MyScrollView;
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI WebView
-
A WebView allows opening an HTML5-based View which can load either local or remote content, and is defined in
Titanium.Proxy → Titanium.UI.View → Titanium.UI.WebView
-
The content can be any valid web content such as HTML, PDF, SVG or other WebKit-supported content types
JavaScript in the WebView executes in its own context
When running local web content (that is, web pages inside the application's resources and not downloaded from the
internet), scripts have access to the Titanium namespace
‣
-
You can use Titanium.App.addEventListener and Titanium.App.fireEvent to receive and send
application-level events
Scripts downloaded from remote
web servers cannot access the
Titanium namespace
Alessandro Grazioli
function MyWebView() {
var self = Ti.UI.createView({
backgroundColor : '#ffffff'
});
var webview = Titanium.UI.createWebView({url:'http://www.yoursite.com'});
self.add(webview);
return self;
}
module.exports = MyWebView;
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI WebView
-
Having images in the Resources folder (or sub-folders thereof) included in a HTML page on an Android WebView is
problematic
-
It may work fine in the emulator, and it may work debugging on the device, but once packaged up for store release
images will not show at all
-
The solution is:
‣
First, for the webview URL use the usual format:
Titanium.Filesystem.resourcesDirectory + 'page.html'
‣
However, within your HTML page use absolute paths for all assets
file:///android_asset/Resources/someimage.png file:///android_asset/Resources/
path/to/someImage.png
Note the file:/// has 3 slashes, not 2
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI WebView
-
Let’s suppose that index.html and myImage.png are both in Resources/html folder
The code in the top block shows how to set the page’s path
The code in the bottom block shows how to link the image in the html page
var webView = Ti.UI.createWebView({
width : '100%',
height : '100%',
top : 0,
left : 0,
url : Titanium.Filesystem.resourcesDirectory + 'html/index.html',
opacity : 1
});
<html>
<body>
<div style="background-image: 'url(\'file:///android_asset/Resources/html/myImage.png\')'">Some text</div>
</body>
</html>
index.html
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI ProgressBar
-
A ProgressBar is used for displaying an ongoing activity with a defined progression and is defined in
Titanium.Proxy → Titanium.UI.View → Titanium.UI.ProgressBar
-
min and max represent the progress limits
Changing the value property causes the
displayed progress bar to update
var win = Ti.UI.createWindow({
backgroundColor : 'white'
});
var pb = Titanium.UI.createProgressBar({
top : 10,
width : 250,
height : 'auto',
min : 0,
max : 10,
value : 0,
color : '#fff',
message : 'Downloading 0 of 10',
font : { fontSize : 14, fontWeight : 'bold' },
style:Titanium.UI.iPhone.ProgressBarStyle.PLAIN
});
win.add(pb);
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI AlertDialog
-
An AlertDialog is a modal view that includes an optional title, a message and buttons, positioned in the
middle of the display, and is defined in Titanium.Proxy → Titanium.UI.AlertDialog
-
You can display a very simple dialog by using
alert('Message');
-
You can define a custom dialog with at most 3
buttons to allow user interaction, specified in
buttonNames property
-
The example shows an Add to favorite button
which, when pressed, presents a dialog to ask
for confirm before saving
-
The cancel property is the index of the button in
buttonNames list that removes the dialog (1 is 'No'
in the example)
Alessandro Grazioli
var favButton = Titanium.UI.createButton({
color : '#000',
top : 25,
left : '1%',
width : 30,
height : 30
});
favButton.addEventListener('click', function(e) {
var dialog = Ti.UI.createAlertDialog({
cancel : 1,
buttonNames : ['Yes', 'No'],
message : 'Would you like to add to the favorites?',
title : 'Add to fav'
});
dialog.addEventListener('click', function(e) {
if (e.index === e.source.cancel) { }
if (e.index == 0) {
alert("Added");
}
});
dialog.show();
});
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
UI icons and splash screen
-
Generally, graphics files can all be placed in the Resources directory
-
By default, iOS will modify the icon graphic you supply to add rounded corners
-
If you're providing Android density-specific versions of splash screens, you'll need to put them within the correct
folder in the Resources/android/images hierarchy
However, if you want to provide different app icons for iOS and Android (both must be called appicon.png), you
can put them into the Resources/android and Resources/iphone directories
You cannot remove the splash screen and for Android it must be name default.png, on iOS Default.png (casesensitive)
‣
Check the following link for folders’ names and images’ sizes
http://docs.appcelerator.com/titanium/3.0/#!/guide/Icons_and_Splash_Screens
Alessandro Grazioli
2015 - Parma
Università Degli Studi di Parma
Distributed Systems Group
Hiding the action bar on Android
-
To automatically hide the action bar when opening a window or tab group, you need to set a listener for the
open event in that the bar can be hidden only after the window has been displayed
-
You have to do that for every Window in your
app for which you want to hide the action bar
in the associated Activity
function MainView() {
var isAndroid = (osname == 'android') ? true : false;
var self = Ti.UI.createWindow({});
//
//
//
//
if
var Window = require('ui/common/NewView');
new Window().open();
-
Get a reference to the activity associated to
the Window and hide the bar
Hide the action bar on Android devices
The action bar can be hidden only after
the window has been opened, so set a
listener for the 'open' event
(isAndroid) {
self.addEventListener('open', function(e) {
self.activity.actionBar.hide();
});
}
return self;
}
module.exports = MainView;
Alessandro Grazioli
ui/common/NewView.js
2015 - Parma