Вы находитесь на странице: 1из 217

Build

native cross-platform apps with Appcelerator


A beginners guide for web developers
Ricardo Alcocer For online information about this book, please visit
www.buildmobileapps.io.
c 2015 by Ricardo Alcocer- All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form or by means electronic, mechanical, photocopying, or otherwise, without prior
written permission of the author.
Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in the book, and the author
was aware of a trademark claim, the designations have been printed in initial caps or all
caps.
Development editor: Cynthia Kane
Technical editor: Fokke Zandbergen
Proofreaders : Terry Martin, Alba Leal, Benjamin Hatfield Cover photography and design:
Janice Go, janicego.com
ISBN 978-0-9961543-0-7 (Paperback) 978-0-9961543-1-4 (electronic book)
2015904352

Contents
1 Meet the Appcelerator SDK
2 The basics of Alloy
3 Alloy Widgets
4 Tabs and Advanced Android Customization
5 TableView, third-party modules and working with Local Data
6 ListView, Web Services and Twitter Integration
7 Working with the Camera and native sharing with social networks
8 Top 10 Tips for successful cross-platform development
A Working with JavaScript
B Installing and configuring Appcelerator
C Submitting apps to Google Play and iTunes

Preface
Not long ago, I was involved in building cross-platform desktop applications for the
medical industry. In the process, I learned a lot about cross-platform technology and
frameworks, as well as the psychological and behavioral aspects of building applications
for users of different operating systems.
In 2009 I started building apps with Appcelerator, and in 2010 I started training web
developers on how to build cross-platform mobile apps with it. I applied my crossplatform experience to the training process, and realized it really made a big difference.
This book is the result of these years of developer training and testing of different
methodologies of teaching Appcelerator to new developers.
To understand cross-platform as a concept, we need to properly define it first. Crossplatform doesnt mean to build an application that runs, renders and behaves in exactly the
same way across all platforms - thatll be a website. Building cross-platform applications
actually means that you use the same tool/framework/language, to produce the binary for
the platforms you support.
Platforms are different, and thats by design. Apple and Google need to create very clear
differentiators in their user experience - and if we add Windows Phone to the mix, the
differences are even more drastic. This is part of their strategy of making their platform
unique, increase adoption, and most of all, keep users from switching to other platforms.
If youre an iOS user, and youre given an Android device, youll most likely feel lost and
will want to go back to iOS, because thats what you know - and the same thing the other
way around. Think about it : If iOS and Android apps look and behave exactly the same
on any platform, then whats making users decide between one platform or the other?
The platforms usability guidelines are created to make sure that your app feels right in the
platform. These guidelines are very different across platforms, and your app is designed
around them. This means that knowing and embracing
vii these guidelines is the key to understand how to design a best-in-class mobile app.
Then, understanding how to work with Appcelerator will allow you to implement these
different designs from a single code-base - and thats what cross-platform is.
Can you build an app with a platform-agnostic design? Yes, in fact you can do that with
Appcelerator, as well as with Xcode or Java. Just keep in mind that doing this is a
conscious developer choice, and not something the platform is forcing you to do.

About this book


This book is written for web developers and people with no previous experience in native
cross-platform mobile development. If youve build a website before and would like to
use that same coding paradigm to build native cross-platform apps (not web apps), then
this book is for you.
This book however, has a lot to offer to Objective-C/Java developers who are getting into
cross-platform, as well as to existing Appcelerator developers who want to get into Alloy,
or want to learn about the proper way of approaching cross-platform development.
As you read, youll also see that this is an opinionated book - instead of being strictly a
book about how to use Appcelerator and/or Alloy, its a book about how to properly be a
cross-platform developer.
The book is organized in two sections: The Basics and Advanced Functionality.
The Basics covers the topics of what the Appcelerator SDK is and introduces the main
concepts of Alloy: Using XML, TSS and JS files, Alloy Themes and Alloy Widgets.
Advanced Functionality is the section where youll build full-blown apps using the Alloy
concepts youve learned, as well as some other platform-specific functionality. Ive paid
special attention to Android-specific concepts, as Ive found theres very little that has
been documented about it, at least within Appcelerator circles. I also include 3
appendixes:
Working with JavaScript : A JavaScript refresher
Installing and configuring Appcelerator
Submitting apps to iTunes and Google Play
The overall concept of the book is not to be the absolute and only guide of
ix all things Appcelerator - that will be impossible. With this book I slowly guide you
through the process of thinking cross-platform and build mobile apps with Appcelerator.
Theres a strong emphasis on UI and UX, what the user sees, and I have intentionally
obscured complex concepts of logic, algorithms and best-practices in JavaScript
development. I strongly believe that building the UI/UX of your app and writing the actual
logic are two different things, and although I deal with both in the sample apps, the main
emphasis is implementing native user experience with Appcelerator.
My vision is that this book will give you, as a beginner, the knowledge you need to build
best-in-class mobile apps with Appcelerator, will start you off with the right foot, and get
you ready for additional learning.
Whenever possible, Im using community-developed components. A fundamental part of
Appcelerator is its developer community, which you should learn to embrace and become
part of, to get the most out of the platform.

Code downloads, updates and getting help

Ive setup the website http://buildmobileapps.io, and Ive created a mailing list. I
encourage you to join the list if you havent done so, as Ill be using it to share
information relevant to this book, such as breaking changes and updates in the installation,
configuration and troubleshooting process.
All the code is hosted on GitHub at http://github.com/ricardoalcocer/ appc_book_code.
For consistency, Ill be using GitHubs built-in issues system to answer questions about
the code. I can also be reached anytime via Twitter as @ricardoalcocer.

Part I

The basics

Chapter 1

Meet the Appcelerator SDK


This chapter covers:
The problems solved by the Appcelerator cross-platform Software Development Kit
(SDK)
Why native is a better option for mobile app development than building a web app
How the SDK works
The difference between the Classic and Alloy syntax
Building your first Appcelerator app
Whether you are web developer starting with mobile, a seasoned iOS or Android
developer who wants to start developing for a secondary platform or you work for an
agency where your clients are constantly asking you for mobile apps, Appcelerator can
help you reach your goals. Why? Because the Appcelerator SDK effectively solves the
problems you face when youre getting into mobile. Heres a short list of the main
benefits.
You use JavaScript, a language that is widely considered easier to learn and master than
Java or Objective-C (the native languages for Android and iPhone respectively)
Youll be able to keep a single code-base and reuse code across different platforms
Youll use the same web development coding paradigm of a markup language,
stylesheets and JavaScript code to add functionalities to your markup
Youll find that its easier to train your team, as its only a matter of introducing them to
the concepts of the Appcelerator API - theyll be building apps in no time
Youll have a much faster time to market and ease of maintainability and scalability of
your app, while obtaining the same results as someone using Java or Objective-C
The Appcelerator SDK is a mobile application development framework developed by
Appcelerator, Inc., with which you write your application in JavaScript and then compile
it into a fully native app using the target platforms Native APIs and SDKs. Throughout
this book Ill be focusing on the two main mobile platforms: iOS and Android.
Supported Platforms
At the time of this writing the Appcelerator SDK supports iOS (iPhone and iPad), Android
(phones and tablets), Blackberry 10, Windows Phone and MobileWeb (Appcelerator code
converted into HTML).
This book is written with web developers in mind. If you know HTML, CSS and
JavaScript, and have built websites from scratch, youll feel right at home because
Appcelerators coding paradigm is very similar to building websites.
Well also be focusing on the proper way of building native cross-platform apps from the

UI/UX standpoint using native SDK-provided screen controls and navigation structures.
You dont have to be an experienced JavaScript hacker either. Although well be
implementing advanced functionalities into our apps, this is not a book about complex
programming patterns or JavaScript best practices.
In this chapter youll see how Appcelerator effectively solves native crossplatform
development problems, such as using native user interface components, and how you can
start building native mobile apps using your current web development skills.

1.1 What is the Appcelerator SDK?


To develop an app for the iPhone, Apple provides the iOS SDK (Software Development
Kit) designed to be used with the Objective-C language. Android on the other hand
provides the Android SDK designed to be used with the Java language. This means that if
you want to release an app for both iTunes App Store and Google Play Market, you need
to write code in two very different programming languages. The Appcelerator SDK is a
cross-platform framework that gives you access to these underlying SDKs but from a
single programming language: JavaScript.
A cross-platform framework should be part of your mobile strategy. When you use a
framework, you dont need a specialized team working on Objective-C and another team
working with Java. These frameworks however come in two different flavors: Web/hybrid
and Native. If youre a web developer, your natural choice is probably a web/hybrid
framework because after all, building a mobile web app is essentially building a smaller
website. However, the reality is that a web app is not THE solution to the cross-platform
problem, but rather part of the solution.
The underlying problem is that developing using the native languages is out of the reach
of a web developer. Lets face it, learning and mastering languages like Objective-C and
Java is not an easy task. The Appcelerator framework solves this problem and as youll
see, if you can build a website, you will be able to build native mobile apps.

1.1.1 How it works


Imagine youve just met two people, one who speaks Chinese and one who speaks
Japanese, but you only speak English. You could learn the languages, but you cant learn
them fast enough to have a conversation today. You resort to finding someone who speaks
both languages to act as your translator.
The Appcelerator SDK acts like a translator above and provides you with a high-level
layer to access native functionalities (see Figure 1.1). This means that if you want to create
a button, a text field, a table, etc., you only have to learn how to create them in JavaScript,
and the Appcelerator SDK will translate and perform the corresponding native call for the
target platform. You dont need to learn Objective-C or Java because by writing JavaScript
youll have access to the underlying native functions. In other words, with Appcelerator,
you are a native mobile developer whos using JavaScript and the results are those of
having written Objective-C or iOS and/or Java for Android.

Figure 1.1: How the Appcelerator SDK works


If youre a web developer with little JavaScript experience, make sure you check out the
JavaScript Refresher on Appendix A
Appcelerator does not simulate screen transitions, animations or platform themes either.
Appcelerator actually uses what the platform provides, and for this reason youll
sometimes find certain features that are available on only one platform. This is actually
not a bad thing, but well explore it in detail in chapter 2.
Appcelerator provides you a JavaScript bridge to access the native SDKs. However,
Appcelerator should not necessarily be seen as a way of avoiding native languages, but
rather as a competitive advantage. If you dont know ObjectiveC or Java and dont want to
learn them, Appcelerator offers all you need. If on the other hand you know either
Objective-C or Java, and you already have a functionality written in either language, you
dont necessarily have to re-code it in JavaScript. For this scenario Appcelerator provides
a Module Development system with which you could inject native code into your
JavaScript apps. This is a very advanced topic that is outside of the scope of this book.
More information can be found in the official guides at http://docs.appcelerator.
com/titanium/latest/#!/guide/Android_Module_Development_Guide
For both platforms you need to obtain the native platform tools. If youre developing for
Android, you need a Windows, Mac or Linux (Ubuntu is recommended) computer to
install the Android SDK and the tools provided by Google for any native Android
developer. If youre developing for iOS you need Xcode, the iOS SDK and you need to
use a Mac (this is an Apple requirement). Apple requires you to have a developer account
for testing on a device and publishing to the AppStore. With Android you can test on a

device without a developer account. As opposed to web app development, even though
youre using web technologies, with Appcelerator you are in fact a native developer of the
platform, but using a cross-platform framework on top of their native tools.
iOS (iPhone, iPod Touch, iPad) Runs only on Mac
Xcode and iOS SDK (free download)
An Apple developer account is required to test on device and publishing to the AppStore Android (Phones and Tablets)
Runs on Windows, Mac or Linux
Android SDK Manager and desired platform SDKs (free download)
Can test on device without a developer account. A developer account is only needed to publish to the Play Store

Table 1.1: Native Platform Tools


The Appcelerator SDK is installed on top of these native tools so the native tools are
requirements for it to work.

1.1.2 The Appcelerator Syntax


Appcelerator apps are written in pure JavaScript. As a web developer, youre used to using
JavaScript as a way of adding functionality to screen controls. With Appcelerator, you use
JavaScript to write all the logic of your app, not only for handling button events. You can
write Appcelerator apps using two flavors: Classic or Alloy.
Classic code : JavaScript-Only
Classic is the original and main syntax for writing Appcelerator apps. Native objects,
regardless of the target platform, are normalized as a single function call. Listing 1.1
shows how to build a simple cross-platform ON/OFF switch. Listing 1.1: Native switch in
Appcelerator Classic
var win = Ti . UI . createWindow ({
backgroundColor : # fff
}) ;
var myswitch = Ti . UI . createSwitch ({ value : true
})
win . add ( myswitch ); win . open () ;

ALLOY : XML, TSS AND JavaScript


Alloy is an MVC framework (Model-View-Controller) that sits on top of Appcelerator to
make your app development super easy. If you are not familiar with MVC, dont worry
about it for the moment, Ill explain in a later chapter. Whats important at this moment
though is that Alloy establishes a clear separation of your user interface code and the code
that defines the behavior of your app, a concept known as loose coupling.
With Alloy you use XML to define the objects on your user interface and use TSS (like
CSS, stands for Titanium Style Sheets) to provide styling to these objects. JavaScript is
only used when you want to add behavior to your user interface. This is often referred to
as separation of concerns and means that everything that has to do with UI goes in one
place, and everything that has to do with behavior goes in another. It also means that if
youre a web developer or graphic designer, you can write the user interface of an app and
then get someone else to work on the behavior, or the other way around.
Alloy also optimizes your code and in many ways prevents you from writing JavaScript

code that may fail or slow down the execution of your app. Figure 1.2 shows how Alloy
works as compared with Classic.
Alloy takes your XML, TSS and JavaScript files and generates from them optimized
Appcelerator code, which is then passed over to the regular Appcelerator cycle.

Figure 1.2: Comparison of Classic and Alloy


In Listing 1.2 well create the same switch as before, but this time using Alloy.
Listing 1.2: Native switch in Alloy
< Alloy >
< Window backgroundColor =# fff >
< Switch id = basicSwitch value = true / >
</ Window >
</ Alloy >

If you run any of these two listings, Classic and Alloy, the result is the same: a native
toggle switch as seen in Figure 1.3.

Figure 1.3: Native


representation of the Switch control
Classic syntax is not going away. This syntax has been around for over three years and has
been used by over 500,000 developers worldwide. However since Alloys release in
February of 2013, its adoption has been overwhelming. Users have not only embraced the
platform, but theres an ever growing number of developers who are actively contributing
code to the project. Alloy is today truly a community-developed open source framework.
For web developers, Alloy simply feels right. Building screens with XML is very similar
to writing HTML code. The use of IDs and Classes on your XML tags is also a familiar
concept, as is styling them from a separate file. Alloy not only makes it easier to organize
and maintain your code, but it also performs many optimizations and normalizations for
you. Youll still need to write JavaScript and Classic code for your controllers, but only
when needed. Keep in mind that Alloy is a layer on top of Appcelerator, designed to make
Appcelerator apps easier to write and maintain. Alloy still generates Classic code, so
Alloy is here to help you be more productive and efficient.

Appcelerator Classic or Alloy


Alloy is a high-level layer, an abstraction, on top of Classic. In other words, Alloy
provides you with a friendlier way of writing Appcelerator code, providing optimizations
and relieving you from getting too much into JavaScript code. This increases your
efficiency and overall coding time.
Alloy apps are written using the MVC (Model-View-Controller) paradigm, so by
definition it will help you write apps faster, clearly separating your screen code (the
Views) from their styling (the Styles) and the implementation of functionalities (the
Controller). In the end, theres nothing you can do with the Classic syntax that you cant
do with Alloy. Alloy simply provides you with a way of organizing your code that is
easier to understand, and ultimately is easier to maintain and collaborate on.
In this book Ill be showing you Classic syntax from time to time, but the focus is on
writing apps using Alloy.

1.2 Building an Appcelerator App


As opposed to websites where you simply save the file and reload the page on your
browser to see the changes, native apps need to be compiled. In the case of Appcelerator,
your code is first compiled by the Appcelerator compiler and then with the native platform
compilers. To help you in your development process, Appcelerator provides an IDE
(Integrated Development Environment) called Appcelerator Studio, which provides you
with the tools you need to configure your environment, write, test, debug and eventually
publish your apps to the application stores. Appcelerator Studio is based on Eclipse, a
well-known Open Source coding editor, and its really easy to use.
Although well be using Appcelerator Studio throughout the book, I should mention that
Appcelerator also has a command-line interface (CLI) that allows you to use your text
editor of choice and the Terminal/Command Window to invoke the build process.

1.2.1 Writing your first Appcelerator App


In listings 1.1 and 1.2 we saw the code for writing a simple ON/OFF switch using Classic
and Alloy. I know this is a very trivial example, but for now I just want to demonstrate
two things: first that Classic and Alloy are just two different ways of doing the same thing;
second that what you get is a native app. This switch is not an HTML DIV using images,
JavaScript and CSS to emulate the platforms. Appcelerator is effectively reading your
Switch instruction and obtaining the native one from the platform SDKs.
Lets go ahead and try the Alloy example in Listing 1.2 and launch it in the native
emulators as shown on Figure 1.4.

Figure 1.4: Native


Switch running on iOS and Android
Launch up Appcelerator Studio and select File >New >Mobile App Project. This will
show you the Project Template window. Select Default Alloy Project and click
Next. Now we need to enter configuration details for this project (Figure 1.5).

Figure 1.5: New Project Configuration


When you have completed this screen click Finish and Appcelerator Studio will open
your new App. Your file explorer is located on the left-hand side (Figure 1.6). Click on
App to expand it and then on Views and double-click on index.xml.

Figure 1.6: Project Explorer


Delete the default code for Index.xml and type the following code, which youll recognize
from listing 1.2
< Alloy >
< Window backgroundColor =# fff >
< Switch id = basicSwitch value = true / >
</ Window >
</ Alloy >

No need to add or change anything else at this point; youre now ready to test your app.
Click on the Run icon as shown on Figure 1.7 and select your target simulator.

Figure 1.7: Running your app


The first time you run your app it will take a couple seconds. Subsequent launches will be
significantly faster.
As opposed to web development, where after you make a change you save and refresh the
browser, in app development youll have to run the app again. When you rerun your app,

on iOS the simulator will shutdown briefly and will come back up, launching your
updated app. For Android, you should avoid closing the emulator, as Appcelerator will
reuse the same instance and simply reinstall the app onto it. Alternatively, Appcelerator
offers a feature called LiveView, which automatically reinstalls your app when you save
your project.
Congratulations, youve just built your first native, cross-platform app for iOS and
Android using Appcelerator! As you can see, Alloy gives you the benefit of writing an
App using an HTML-like syntax. Notice also that achieving these results from a web app
would have required more lines and code, plus the inclusion of stylesheets and pre-built
JavaScript libraries.

1.3 Summary
With the Appcelerator SDK you get access to the native SDKs straight from your
JavaScript or Alloy code. Each platform SDK contains a host of native UI controls (Text
Boxes, Buttons, Switches, etc.) and navigation structures designed to provide consistent
look-and-feel and app behavior. By using the platform-provided controls, you dont need
to use CSS/JavaScript UI frameworks to emulate the user interface. Understanding and
embracing these entities will ensure that your app always looks and behaves like the
platform its running on, not to mention the amount of time you save by not having to
create your own navigation structures. In chapter 2 well dive into these UI controls, well
learn when to use them, how they render across platforms and how to make cross-platform
UI/UX decisions for your mobile app.
What to remember about the Appcelerator SDK:
With Appcelerator you use JavaScript, a language you already know and that is easier to
learn and master than Java and Objective-C
You can keep a single code-base for your app regardless of how many platforms youre
targeting
You use the Web Development paradigm of a markup language, stylesheets and
JavaScript and obtain native apps
You can train your development team in a fraction of the time required to learn the native
platform tools
You can dramatically speed up your time-to-market and end up with a cross-platform app
that is easy to maintain and scale

Chapter 2

The basics of Alloy


This chapter covers:
The MVC framework and how it is applied to Titanium using Alloy
How to create a strategy for building mobile user interfaces
How to write Alloy XML, TSS and JavaScript files to build a fully working project
In chapter 1 we saw how Appcelerator introduced Alloy to make it easier for web
developers to cross the gap from web development to mobile development. In this chapter
well take our first steps towards learning how to work with Alloy by developing our first
app, an MP3 player.
Arguably, the most important part of an app is the user interface. However with traditional
app development (and with Titanium Classic), user interface designers are left out of the
equation when building mobile apps, and their involvement is reserved to simply creating
graphic files. With Alloy, anyone who has built a website and knows about web
development concepts can not only build native user interfaces, but also build fully
working apps. This is a huge step forward, as user interface designers can now formally be
part of the development team, and all this is possible because of Alloy.
Alloy will allow you to write your code in a declarative markup language, just like
HTML, and apply styles using stylesheets just like CSS. Theres a lot to cover about Alloy
so well take it one step at a time. In this chapter well be exploring the very basics,
enough to build a fully working app. By the end of this chapter youll have a clear
understanding of how Alloy works and how you can use your existing HTML and CSS
knowledge to start building native mobile user interfaces.

2.1 What is Alloy?


Alloy is an MVC (Model-View-Controller) framework implemented as a highlevel
abstraction on top of Titanium Classic. By high-level abstraction I simply mean that Alloy
is a piece of software that still runs on top of Titanium Classic, but exposed to the
developer in a different way, as seen in Figure 2.1.

Figure 2.1:
Relationship between the platform SDKs, the Titanium API and Alloy
Think of it this way: You could bake a cake gathering all your ingredients one by one,
baking powder, flour, etc., or you can buy a mix to which you only need to add water. This
mix is your framework for baking cakes. Alloy does this for Titanium.
Alloy code is much easier to organize because the concept of MVC is to keep UI code in
one side, styling in another, data models in another, and the code 2.1. What is Alloy?
that binds the UI to the logic of your app in another. The result is source code that is easier
to write, maintain and scale.
To make it friendlier to web developers, Alloy uses a declarative markup language to build
the user interfaces, that is very similar to HTML. Styling is applied using stylesheets
(called Titanium Style Sheets or TSS) similar to CSS, and then uses pure JavaScript to
implement functionalities using the Titanium API. In the following section, Ill give you
an introduction of how the Titanium API is laid out, and how to use it in your mobile apps.

2.1.1 The Titanium API


The Titanium API is the core of Titanium, and is what extends JavaScript so it can be used
for mobile development. With Alloy youll still write some JavaScript code, but
understanding how the API is laid out is crucial to understanding how Alloy works and
what it can do for you.
The Titanium API has thousands of objects, methods, properties and events, so we wont
look at each and every one of them. They do follow a consistent pattern so once you learn
how to use one or two of them you essentially know how to navigate through the rest.
Make sure you bookmark the official online reference located at
http://docs.appcelerator.com/titanium/latest/#! /api as it will become your best friend.

At the JavaScript level, Titanium functions are part of a high-level object called Titanium.
Figure 2.2 shows the namespaces available in the Titanium API. Inside the top-level
object are different sub-objects called namespaces. For example inside the UI (User
Interface) namespace youll find functions to implement user interface objects.

Figure 2.2: How the Titanium API is organized


Lets take for example the Window. The Window object is located inside Titanium.UI, and
to create one you use the Titanium.UI.createWindow function, for example:
var win = Titanium . UI . createWindow ({
backgroundColor : red
}) ;

Ti is a shortcut for Titanium, so you could either write Titanium.UI.createWindow or


Ti.UI.createWindow.
In this example the variable win will contain a Window object and weve assigned red
as its background color. If we look at the Button, it also lives inside Ti.UI and to create
one you call Ti.UI.createButton, for example:
var loginButton = Ti . UI . createButton ({
title : Login
}) ;

In this other example the variable loginButton contains a Button object with Login as its
title. Other namespaces are Media, Map, Network, Filesystem, and many others, but you
dont have to memorize them all. As you start developing apps youll see yourself needing
a particular functionality and finding the reference in the official documentation.
The Titanium API is the set of objects and functions that expose to JavaScript the
functions of each platform SDKs. Since Alloy is a framework on top of the Titanium API,
you still need to have a clear understanding of how the API is laid out. Later in this
chapter youll see in context how these namespaces relate to Alloy and how to use them in
your own apps.

2.2 Understanding MVC

To understand what MVC is, why its important and how Titanium implements it, lets
first take a deeper look at Titanium Classic, which is non-MVC code, on Figure 2.3.

Figure 2.3: NonMVC Titanium Code


This works perfectly fine and you can write full apps this way. In fact, many developers
still prefer writing apps this way, mainly because they have large code bases already
written and its too expensive for them to migrate to Alloy, or simply because they dont
have a web development background, so using Alloy is not really that friendly to them.
Theres also one inherent disadvantage to writing apps this way and its that it follows a
practice called tight coupling. Tightly coupling means that you combine user interface,
styling and behavior instructions in the same source code. Youll see this more clearly in
Figure 2.4.

Figure 2.4: Tight


coupling in Titanium Classic
In Figure 2.4 you can see how the code combines user interface code with styling and
behavioral code. The Window and the Button are user interface elements, the color of the

Window is a styling property and the handler for the click implements the behavior of the
button.
As a web developer you see this all the time with styles defined inline within the HTML.
It is considered a very bad practice; all styles should be specified as stylesheets. If you
need to make changes to the UI, you make them from the outside, and oftentimes you
dont have to touch the HTML at all.
This doesnt necessarily mean that Titanium Classic is not good - far from it, but in order
to follow best coding practices, developers ended up creating their own ways of separating
UI, styling and behavioral code.
MVC is not a new concept, nor is it exclusive to mobile development or Titanium. MVC
has become a de-facto standard in building applications of all types and for different
programming languages and modern software developers often look for frameworks that
implement the MVC paradigm because of its many advantages. Alloy represents
Appcelerators official response to this question.

2.2.1 Getting to know Alloy


Alloy separates your code into files that belong to different tasks within your development
cycle as seen in Figure 2.5. The main files in an Alloy screen are the XML, TSS and JS,
and the three work together.

Figure 2.5: Alloy


MVC
Table 2.1 describes what each file is for. The XML file defines your user interface
elements. The TSS file defines styling properties of these elements, while the JS file
implements functionalities.
MVC Component View and Stylesheets Language XML + TSS
Controller JavaScript
Model Backbone

Description
Alloy views follow the same paradigm used for web development, and are composed of a combination of two files: XML and TSS. The XML file is
used to specify the components of your screen, such as buttons, text fields and images. The TSS (Titanium Style sheet) file works together with the
XML file to provide styling to the components of your screen.
The Alloy controller is a JavaScript file that has access to your XML view. From this JavaScript file you can access the components of the screen,
assign and respond to events and write your screens programming logic.
Alloy models use Backbone.js, a popular JavaScript library. Backbone provides you with a user-friendly programming interface to create local data
stores.

Table 2.1: Alloy MVC Components


For all practical purposes, all you need to know about MVC is that it provides a structured
and de-facto standard way of organizing your code, separating responsibilities in the
developer team, and ultimately making it much easier to maintain, debug and scale.
When you create an Alloy app it will automatically create 3 files for you: index.xml,
index.tss and index.js corresponding to your first view context. Alloy looks for files by
their name, so it knows that index.tss has the styling for index.xml, and index.js has all the
code for index.xml. Furthermore, your Window inside index.xml will have an implicit id
of index, which is used to refer to this View from your controller code, but more about
this later.
When youre building an app using Alloy, the person doing the UI part still has to step
into the controller code from time to time, but not necessarily to implement complex
functionality, but rather to the same level a designer goes into the HTML and adds HREFs
to a link or to modify images on a CSS-based image slider. Well see this in context in the
following pages. For now, lets explore the basics of writing apps with Alloy by exploring
the different file types one by one.

2.2.2 Alloy Views (XML)

Alloy Views consist of two files: the XML that defines the contents of the screen and the
TSS that defines the styling. The XML file always starts with the <Alloy >tag and ends
with </Alloy >, and between these tags you place the user interface components required
for your window.
In simple terms, a View is used to hold something that will appear on the screen

something that will be seen by the end user. The most common case is to use a View to
represent a Window, in which case your <Alloy >tag will be followed by a <Window >tag,
and inside this <Window >tag youd add your user interface elements.
View files are not exclusively used for Windows. As youll see in future chapters, you can
use View files to represent chunks of code that will be reused across other views, or to
hold templates for list rows that will be repeated inside a loop in your controller code.
Lets look at a side-by-side example of Titanium Classic and Alloy in Figure 2.6.

Figure 2.6:
Titanium Classic and Alloy side-by-side
In the image above you can see that Alloys XML is much more readable and easier to
understand than its pure JavaScript counterpart. Also notice that were only defining that
these components exist and all styling will be added to an external TSS file.
Alloy tags are very similar to HTML tags and in Figure 2.7 you can see the components of
a typical tag. Note that the height and width properties are included only to illustrate that
they are allowed within the tag. As mentioned earlier, it is a bad practice to couple UI and
Styling code. In section 2.2.3 youll see how to use TSS files to provide styling properties.

Figure 2.7:
Anatomy of the XML tag
Titanium has a user interface component called View located at Ti.UI.View. This
component is not to be confused with the Alloy View we saw earlier. The View in Alloy
refers to the View in Model-View-Controller, while the former refers to an actual user
interface object very similar to the DIV in HTML
In Figure 2.7 above we use the <Label >tag. These tags, although they look like HTML,
are actually representations of the Titanium API living underneath. For the Label tag,
there is a Label object in the Titanium UI namespace, and the tag is bound to the
createLabel method described at http://docs.
appcelerator.com/titanium/latest/#!/api/Titanium.UI.Label.
All Alloy XML tags map directly to the Titanium API, which is why you should be
familiar with the underlying Titanium factory methods. Earlier we saw
Ti.UI.createWindow and Ti.UI.createButton. To know the corresponding Alloy XML tag,
simply remove Ti.UI.create and the remainder is your XML tag, that is <Window >and
<Button >starting with a capital letter, and naturally, just like in HTML, all tags require a

closing tag with a forward slash, for example </Window >.


Ti.UI is the default namespace for Alloy. If the object youre trying to use does not belong
to Ti.UI, such as Ti.Map.View, then youll have to add a special namespace (ns) attribute,
for example <View ns=Ti.Map, which refers to Ti.Map.View. Well see more about this
case in a future chapter. Also, theres a special module attribute that will allow you to
create you own tags. Using this attribute is outside the scope of this book but you can find
more information about it at http://docs.appcelerator.com/titanium/latest/#!/guide/Alloy_
XML_Markup-section-35621528_AlloyXMLMarkup-ModuleAttribute.

2.2.3 Alloy Stylesheets (TSS)

Lets now take a look at the second component of the Alloy View, the TSS file. Titanium
Stylesheets (TSS) are very similar to CSS in function, but a little bit different in structure
as seen in Figure 2.8.

Figure 2.8:

Comparing TSS to CSS


The reason for these differences is that TSS files are actually JSON files, so the
construction conforms to the JavaScript object specification. Object names are defined as
strings, followed by a colon and then a JavaScript object with a dictionary of properties
and values. Lets build the TSS file for our previous example to add color and positioning
for the window and button.
. container :{
backgroundColor : red
}
. button :{
top : 5,
left : 5
}

From Titanium Stylesheets you have access to the properties of the objects provided by
the Titanium API. The concept is very similar to CSS, but remember, youre not using the
DOM.
At first youll see yourself going back and forth to the API documentation to understand
which properties are available for each object, but in no time youll realize that most
object share the same property names, so theres actually very little youll have to
memorize. In the coming chapters well see how TSS files can be separated as themes and
how they can even have conditional operations within them.

2.2.4 Alloy Controllers (JS)

The controller is where you add your actual JavaScript code. Up to this point youve
created a Window and have applied styling properties. But your screen is completely
static. The controller file is the place where you make your screen do something useful.
From your controller youll have automatic access to all your screen components. Our
previous example defined a button inside the screen:
< Button id = mybutton class = button onClick = doclick > Click Me </ Button >

Notice that we defined an onClick event to which we assigned a function called


doclick. This function belongs inside the controller file. Lets create it now.
function doclick ( evt ) {
alert ( Thank you for clicking ) ;
}

The doclick function is a simple JavaScript function that is calling JavaScript alert
function to show a message on the screen. Notice that this function has one argument, evt.
The name is arbitrary, but it stands for event and it simply means that this function will
receive an event object, containing information about the object that generated the click
event, in this case the Button. This is really not that much different to the way you build
JavaScript function for the browser.
Theres still one little detail we need to address, and that is that since this is our first (and
only) window, we need to explicitly open it. But the Window was defined in XML. How
can we get access to the XML from the JS file? Well, Alloy has a built-in object called $
and it provides direct access to the XML file as shown in Figure 2.9. In fact, when reading
Alloy code with a $, it could be read as this view.

Figure 2.9: The


Alloy dollar sign symbol
The structure for using the $ symbol is to follow it by a period and then follow it by the Id
of the object you want to access. For example $.mybutton (read the mybutton object of
this view) will return a reference to the Button object because mybutton is the Id of said
button. But the Window has no Id, how can we access it? As mentioned earlier in section
2.1.1, the first window of your app has an implicit Id of index, thats why Figure 2.9
uses $.index even when no Id is set. For all other windows though, youll have to
explicitly add the Id property in order to gain access to them from your JS file.
By calling $.index, were obtaining a reference to the Ti.UI.Window object mapped to the
Window tag. This means that we can now talk to this object, change properties, obtain
data from it, or call any of the object methods. For our example we need to call the Open
method, so we write $.index.open() and the window will be properly opened and be ready
for user interaction.

2.2.5 Alloy Models (Backbone)

The last component in the MVC pattern is the Model. The Model, short for data models, is
where you define structured databases for your app. Alloy models are implemented using
Backbone.js, a popular open source JavaScript library that gives structure to web
applications providing features like data collections and custom events.
Alloy can provide you with easy access to local databases as well as establishing complex
connections to web services and perform data synchronizations between the phone and
remote data sources. Not all apps use data models and although Backbone is part of Alloy,
you could still establish data connections without using Backbone. For the time being, you
just need to know that its there, but we wont need it for our example. In this book well
not get too deep into Backbone as it is a complex topic that requires a longer discussion.
Well however get into a very simple implementation in Chapter 6. For more information
about Backbone visit http://backbonejs.org/ or the official Alloy Models documentation at
http: //docs.appcelerator.com/titanium/latest/#!/guide/Alloy_Models.

2.2.6 What happens under the hood


Besides providing a more intuitive way of organizing your App, Alloys power actually
lies in the things it does for you with the code.
When you run your app, Alloy takes your trio of files, the XML, TSS and JavaScript
(and any other file related to the project) and actually writes an optimized JavaScript
version of all three, written as a CommonJS module using Titanium Classic syntax. If
youre curious, you can look at the Resources folder, in which you can see the code thats
generated by Alloy. This generated code is what eventually will go through the Titanium
compiler.
CommonJS is a technical specification for writing JavaScript modules. See more at:
http://wiki.commonjs.org/wiki/CommonJS
Thats right - in the end Alloy is helping you to write optimized JavaScript apps. Alloy
also takes care of normalizing many APIs, as seen on Figure 2.10.

Figure 2.10: Alloy


normalizes API calls
In the code above we are creating a Button that with the caption Click Me and a Label
that with a caption Enter name. Both functions look very similar in format and structure,
but the property used for the button caption is named title, while the one for the label
caption is named text. This may seem insignificant, but believe me, keeping track of
property names and knowing which belongs to which object is a process that takes many
hours of constant coding.
What Alloy does for you
Theres no need to handle the code for assembling the view hierarchy. The view XML
does that for you.
Theres automatic normalization of Titanium API calls.
Best practices are baked into the UI creation. The fastest, safest, full cross-platform UI
construction is used under the hood so the developer never even needs to study them to
take advantage of them.
The ability to optimize code at compile time that formerly had to be done at runtime.
Since Alloy is a pre-compiler that generates Titanium code, all the conditional operations
to target different platforms are performed at pre-compile time, boosting runtime
performance by completely eliminating code not needed for each target platform.
Drastically reduce the need to put programmatic style handling in the controller code.
With Alloy you dont have to remember the property name used for either of these two
objects. The Alloy pre-compiler internally knows that for a button it should use title and
for a label, text; it is all done for you. This is only a trivial example; there are many other
APIs, such as ScrollView, TableView, CoverFlow and others that differ in syntax on the
Titanium Classic side, but are simply specified in XML as a hierarchy of objects. Well see
more of this in coming chapters.
Finally, Alloys style processor and its platform-specific properties, which well explore
later in this chapter, provide a much more organized and secure way of writing more
granular cross-platform code.
In this section we saw how Alloy uses different files to separate your code. These
optimizations not only make your code perform better, but keep your code organized and
easy to maintain and scale. With all this new knowledge we have all the components we
need to understand how Alloy works and in the next section well build our first full app.

2.3 Building an MP3 Player


Lets put all of this information in context by building an App. Well be building a special

purpose MP3 player. Mobile devices come with MP3 players, but the one well be
building will include the tracks itll play. Please dont underestimate this example. Ive
used this code virtually unchanged for several projects. What is this good for? Think about
an artist that would like to release a couple new songs through an app; or think about
guided tours in a museum or national park. The possibilities are endless.

2.3.1 Planning your app


The first step towards building an app is planning. This stage is when UI and functional
decisions are made. Figure 2.11 shows how we want our MP3 player to look.

Figure 2.11: How


our MP3 will look on iOS and Android
Notice that both the iOS and Android versions look very similar. The biggest difference is
the windows title bar. Lets look closer at it in Figure 2.12.

Figure 2.12: Differences between the iOS Title Bar and Androids ActionBar Heres where

knowing how iOS and Android work and how Titanium gives you access to native
controls come in handy. Android windows have a component called ActionBar, which is
consistent across all windows in your app, and across all Android apps. On the other hand,
iOS has a Toolbar control. They both serve the same purpose, but notice how on iOS the
title is centered across the Window, while on Android it includes the App icon and the text
is aligned to the left. Dont try to make the two apps look exactly the same, dont try to
remove the icon on the Android side and dont try to have the title centered in both
versions. This is the way the operating system works and as you start using native controls
and embracing their behavior, youll realize how much time youre saving by not having
to build controls yourself. Besides, by using these conventions, your app will look and
behave as any other native app and in the end itll be easier to adopt by your users.
From the functional standpoint we need to know that our app will:
Play MP3 music bundled with the app
The name of the song currently being played will be displayed in the center of the screen
The Play button needs to change to Stop when playing and to Play when stopped
Pressing Next will move you to the next song unless youve reached the end, in which
case it will do nothing
Pressing Previous will move you to the previous song unless youve reached the
beginning in which case it will do nothing
Having made functional and cross-platform UI decisions, we are now ready to start
building this apps user interface. Well divide the development of this app into two
milestones, the first one for building the UI and the second one to implement the
functionalities.

2.3.2 Milestone 1 : Building the UI


Launch Titanium Studio, select New >Mobile App Project from the file menu, select
Alloy and then fill-out your app details; use Figure 2.13 for reference.

Figure 2.13:
Creating a new mobile project
If youd rather import the code from the companion code package, Figure 2.14 shows you
the steps.

Figure 2.14:
Importing projects into Studio
Lets start by looking at the user interface components well need for this project,
described in Table 2.2. Its always a good idea to create an inventory of required user
interface elements before starting any project.
Component Window
Toolbar
ActionBar
View
Label
ImageView Description
Main app container
Placed on top of the window on the iOS version.
Placed on top of the window on the Android version. The ActionBar will be added on the onOpen event of the Window. Used as an object container.
Similar to the Div in Web Development. Can be of a fixed size or stretched to fit a certain area. Well use it to create the bottom area holding the
control buttons.
Used to add text to the window. Well use it to add the title of the Window and the title of the song currently playing. Used to add images to the
window. Well use it to create the actual previous, play, stop and next buttons, and well use the onTouchStart and onTouchEnd events to give the
button down and button up effect.

Table 2.2: User interface Components required for the MP3 Player
Looking at this UI as a web page we can establish the strategy for dividing our screen. In
Figure 2.15 you can see that well divide our screen into three sections.
Top: On the top well place the Toolbar or ActionBar.
Center: The remainder area well call content and thats where well place the title of the
track currently playing.

Bottom: The bottom section well call Controls Bar and thats where well place our
media player controls.

Figure 2.15: MP3 Player Skeleton


Notice that were adding the controls bar area inside the content area. Later on youll see
that by doing it this way were letting Titanium Figure out the actual positioning of the
objects instead of performing complex and potentially brittle calculations by hand. With
this information in mind we can start writing our XML file. Below is the basic structure of
our window.
< Alloy >
< Window class = container onOpen = doopen >
< Toolbar platform = ios >
< Items >
< FlexSpace / >
< Label id = windowtitle / >
< FlexSpace / >
</ Items >
</ Toolbar >
< View class = content >
< Label id = songtitle class = songtitle > </ Label > < View class = controlsbar > </ View >
</ View >
</ Window >
</ Alloy >

In the code sample above we have our basic skeleton. Weve also added some special
attributes and components:
The onOpen event specifies the function to run when the Window is actually opened.
This doopen function will be defined in our Controller (JS File)
We used a special Alloy attribute called platform. In this attribute you add the

platforms to which you want this tag to apply. By default all Alloy tags will take effect on
all target platforms. As mentioned earlier, the Toolbar component is an iOS-only element,
so we need to specify that itll be only considered for this platform, otherwise the Android
build process will complain of not knowing what a Toolbar is. Well also be using this
technique inside our TSS and JS files, and its one of Alloys most powerful features,
designed to allow you to use a single code-base to achieve platform-specific
functionalities.
The Toolbar needs to contain a sub-tag called Items, to which we add the user interface
elements we want it to contain. For this project we only want a Label, but to have it
centralized, we add the special FlexSpace on each side of the label, causing it to be
automatically centered.
The FlexSpace is a special iOS button type that will create a flexible/stretchable
transparent area, used to position toolbar buttons and to easier create automatic layouts.
The Android ActionBar
Before we continue, lets do some basic ActionBar setup. Android apps show the
ActionBar by default, but its shown using a dark theme where the ActionBar is black. For
our app we need to use the Android light theme. Ill explain this in details in Chapter 4
when we get into ActionBar Styles, but for the moment go to your apps root folder (the
one with tiapp.xml) and create the folder structure platform/android/res/values. Inside this
folder create a file name builtin themes.xml and add the following contents.
<? xml version =1.0 encoding = utf -8? >
< resources xmlns : android = http :// schemas . android . com / apk / res / android >
< style name = LightDarkBar parent = Theme . AppCompat . Light .
DarkActionBar / >
< style name = Light parent = Theme . AppCompat . Light / > < style name = Dark parent = Theme . AppCompat / >
</ resources >

This code tells Android that you want to have access to some built-in themes, in this case
defined as LightDarkBar, Light and Dark. Then go to your tiapp.xml and add the
following to the android section.
< manifest >
< application android : theme = @style / Light / >
</ manifest >

The creation of the builtin themes.xml file and its content is not Titaniumspecific, but part
of Android native development. If you know how to build Android apps, then this works
exactly as if you were using it from Java.
Here youre telling your app which theme you want to use, in this case Light. Thats all
you need to know about the ActionBar for the moment, but as I said, well get back to it in
Chapter 4.
Lets now continue by working with the button strip that will be displayed on the bottom
of the screen. To build this, well use our web development knowledge. Figure 2.16 shows
the skeleton of this buttons area.

Figure 2.16:
Strategy for building the buttons strip
To build the controls button we use essentially the same approach youd use for a web
page. In HTML you have the Div, a UI component that serves as a visible or invisible
frame that can hold other objects. The control analogous to the Div is the View. Well use
one view that well call controlsbar thatll represent the container for the buttons, and
well assign a class name of controlsbar, as seen in Figure 2.17.

Figure 2.17: Main buttons container


Inside this main container view well add three other views to represent the actual buttons.
Well assign to these a class that well call button, and theyll be stacked one next to the
other, occupying the whole width of the screen (Figure 2.18). The specifics for this
positioning will be added to the Views TSS file.

Figure 2.18: Views


to hold each button image
Notice that were using classes and ids. These behave just like HTML and CSS. A class is
used to provide a group of styling properties that can be assigned to multiple objects. Ids
on the other hand can be used for styling properties, but their main function is to have a
unique name so you can later refer to them via code.
Finally, well add ImageViews inside each of these buttons, which will hold the image that
represent the Previous, Play, and Next buttons (Figure 2.19). Notice that were adding the
onTouchStart and onTouchEnd events. These events will take care of handling the action
of clicking on each button. Well see the implementation when we look at the controller
for this view.

Figure 2.19: Adding images to buttons


Thats all we need to do for our screen. Below in listing 2.1 you can look at the full source
code. Listing 2.1: index.xml
< Alloy >
< Window class = container < Toolbar class = toolbar < Items >
< FlexSpace / >
< Label id = windowtitle / >
< FlexSpace / >
</ Items >
</ Toolbar >
< View class = content >
< Label id = songtitle class = songtitle > </ Label > < View class = controlsbar >
< View class = button id = prev >
< ImageView class = btnprev onTouchstart = prevdown onTouchend = prevup / >
</ View >
< View class = button id = play >
< ImageView class = btnplay onTouchstart = playdown onTouchend = playup / >
</ View >
< View class = button id = next >
< ImageView class = btnnext onTouchstart = nextdown onTouchend = nextup / >
</ View >
</ View >
</ View >
</ Window >
</ Alloy >

Lets now start writing the styling in the TSS file. As explained earlier, the
TSS file is similar to a CSS file, but the syntax is like a JSON object, because
the file is essentially a JSON file. Our first entry will be to style our container
onOpen = doopen > platform = ios >

class, which corresponds to our Window. Just like in the XML file where we used the
platform attribute to provide platform-specific components, well do the same to provide
two different sets of properties, one for iOS and one for Android.
. container [ platform = ios ]: {
backgroundColor : white ,
top :20 ,
statusBarStyle : Titanium . UI . iPhone . StatusBar . LIGHT_CONTENT , layout : vertical ,
orientationModes : [ Ti . UI . PORTRAIT , Ti . UI . UPSIDE_PORTRAIT ]
}
. container [ platform = android ]: { backgroundColor : white ,
layout : vertical ,
orientationModes : [ Ti . UI . PORTRAIT ]
}

In the code above were taking care of several important details. BackgroundColor is selfexplanatory. We are assigning a top value of 20 for iOS so our window starts exactly after
the statusbar, otherwise the window will start at the top, falling under the statusbar. Lets
look one by one at the rest set of properties in Table 2.3.
Property Description
statusBarStyle iOS property to control the look and
feel of the status bar on the top of

the screen. Possible values are: Tita


nium.UI.iPhone.StatusBar.DEFAULT,
Titanium.UI.iPhone.StatusBar.GRAY,
Titanium.UI.iPhone.StatusBar.GREY
Titanium.UI.iPhone.StatusBar.LIGHT CONTENT
Titanium.UI.iPhone.StatusBar.OPAQUE BLACK
Titanium.UI.iPhone.StatusBar.TRANSLUCENT BLACK layout The layout property is available for
Windows and Views, and specifies how
the children of this container will be
displayed. Default value is absolute,
meaning that youll have to specify top,
left, right and bottom positions your
self. Default positioning is centered
within its parent. Horizontal layout au
tomatically stacks children from left to
right one next to the other. Vertical
layout stacks children from top to bot
tom, starting in the top position of the
container.
orientationModes This property specifies the al
lowed orientations for the Window.
Were using Ti.UI.PORTRAIT and
Ti.UI.UPSIDE PORTRAIT for iOS,
to prevent the screen from going
into landscape mode. We only use
Ti.UI.PORTRAIT on Android because
UPSIDE PORTRAIT is only available
on iOS.

Table 2.3: Properties for the main window


Lets now take care of styling the toolbar, placing it on the top and enabling the top and
bottom borders.
. toolbar :{
top :0 ,
borderTop : true ,
borderBottom : true
}

Our next class is the content area, to which well assign a background image.
This will be located in the app/assets folder of your project. When Alloy compiles
your app, this assets folder will become your root folder, so to refer to the image
goldengate.png, we use /goldengage.png and not /assets/goldengate.png.
. content :{
backgroundImage : / goldengate . png
}

Now lets provide styling to the songtitle class.


. songtitle :{
font :{
fontSize : 45 ,
fontWeight : bold
},
textAlign : Ti . UI . TEXT_ALIGNMENT_CENTER , color : # fff ,
left : 10 ,
right : 10
}

The left and right properties with a value of 10 are used to provide a padding of 10 pixels
on each side. Since songtitle is a child of container, which has the default absolute
positioning, the songtitle label object will automatically be centered across the screen.
Finally we assign a white color and set the text within the label to be centered.
The next group of classes and ids will be used for styling the controls of the MP3 player.
. controlsbar :{
bottom :0 ,

height :70 ,
backgroundColor :# cacaca ,
opacity :.5
}
. button :{
width : 33% , height : 50
}
# prev :{ left : 0
}
# play :{}
# next :{ right : 0
}

Thats all for the user interface. If youre curious at this point, you could run the project,
but before you do that, youll need to open up index.js and create placeholders for the
functions that weve referenced in Index.xml. Listing 2.2 shows Index.js with the required
placeholders, which well fill out in the next section.
Listing 2.2: index.js with function placeholders function doopen ( evt ){
}
function prevdown ( evt ){
}
function prevup ( evt ){
}
function playdown ( evt ){
}
function playup ( evt ){
}
function nextdown ( evt ){
}
function nextup ( evt ){
}
$. index . open () ;

In the previous listing we are simply creating empty functions. There is no problem in
leaving them empty; at this point Alloy only needs to know they exist. Run the project and
you should see the user interface as it is so far.
In this section we built a full user interface in XML and applied the corresponding
stylesheets using the TSS file. Dont forget that the whole concept is to build your user
interface from the same source code even if its going to be rendered differently. Know the
target platforms, how they behave and what the user expects from the app, then use
conditional attributes to separate your UI and styling depending on the platform.

2.3.3 Milestone 2: Implement functionalities


Lets build the functionalities of our MP3 player by working directly in the index.js file.
Well start by defining some required variables.
var songs =[
{ filename : / songs / file1 . mp3 , filetitle : This is song 1 } , { filename : / songs / file2 . mp3 , filetitle : This is song 2 } , { filename : / songs /
file3 . mp3 , filetitle : This is song 3 } ,
]
var thisWin =$ . index ;
var winTitle = Media Player ;
var currentSong =0;
var audioPlayer = Ti . Media . createSound () ;

In the code above we first create an array with all our MP3 files. This array consists of
JavaScript objects containing the file name, which will be used for the actual Sound Player

and the file title, used for displaying on the screen.


We then store a reference to $.index in the variable thisWin. This is not strictly necessary
but getting used to doing it in all your controllers will provide an extra level of readability
to your code, since you establish the name of the view in one place and then refer to the
thisWin variable throughout the rest of your code. The audioPlayer variable will hold an
instance of the Titanium Sound Player and will be used for playing our songs.
Now lets move on to the doopen function that will be executed when your window is
opened.
function doopen ( evt ){
if ( OS_ANDROID ){
thisWin . title = winTitle ;
} else {
$. windowtitle . text = winTitle ;
}
updateScreen () ;
}

In this function we first take care of assigning the title of the Window. Since we are using
an ActionBar on Android and a Toolbar on iOS we need to write conditional code. Just
like the platform property in our XML and TSS files, Alloy has special variables for
platform-specific operations inside controller. In this case were using OS ANDROID to
make sure the Android-specific code is not run under iOS.
In the case of iOS we simply use the syntax $.windowtitle.text=winTitle, as explained
earlier, to get access to the label in the XML file with id = windowtitle. NOTE
This book focuses on iOS and Android, so well only be using the OS ANDROID and OS
IOS conditional variables. However, keep in mind that you could also use OS
BLACKBERRY and OS MOBILEWEB if your app is targeting either of these platforms.
Now lets take care of the placeholder functions we created in the previous milestone.
function prevdown ( evt ){
evt . source . opacity =.5;
}
function prevup ( evt ){ evt . source . opacity =1; moveback () ;
}
function playdown ( evt ){ evt . source . opacity =.5;
}
function playup ( evt ){
evt . source . opacity =1;
if (! audioPlayer . isPlaying () ){
evt . source . image = / btnstop . png playsong () ; # F
} else {
evt . source . image = / btnplay . png stopplayer () ;
}
}
function nextdown ( evt ){ evt . source . opacity =.5;
}
function nextup ( evt ){ evt . source . opacity =1; moveforward () ;
}

When we defined the View in index.xml we assigned two events to each button:
onTouchStart and onTouchEnd. These events are handled here by the functions with
names ending on up and down. As mentioned earlier, functions for screen events receive
an event object, which we are calling evt. The down functions essentially change the
opacity of the image to make it slightly transparent, providing the user with visual

feedback when the buttons are pressed. We do this by calling evt.source and itll give us a
reference to the object that generated the event and access to its properties. The up
function is called as soon as the touch ends (when the finger releases the button). Here we
set the images back to their normal state of opacity=1, and then execute the actual function
for this button.
The case of the Play button is different because the button has two possible states: Play or
Stop. Well use the isPlaying function provided by the Sound Player. If the player is not
playing (!audioPlayer.isPlaying()), it means that we must set it to play, so we change the
image to the stop image.
Lets now implement the functions that will actually play, stop and move around the
songs.
function moveback () {
if ( currentSong > 0) {
currentSong - -;
if ( audioPlayer . isPlaying () ) {
stopplayer () ;
playsong () ;
}
updateScreen () ;
}
}
function playsong ( evt ) {
audioPlayer . url = songs [ currentSong ]. filename ; audioPlayer . play () ;
}
function stopplayer () { audioPlayer . stop () ; audioPlayer . release () ;
}
function moveforward () {
if ( currentSong < songs . length -1) { currentSong ++;
if ( audioPlayer . isPlaying () ) {
stopplayer () ;
playsong () ;
}
updateScreen () ;
}
}

The only thing left to do is to create the updateScreen function and open the window.
function updateScreen () {
$. songtitle . text = songs [ currentSong ]. filetitle ;
}
$. index . open () ;

There we have it: a fully working, cross-platform native MP3 Player. In this section we
built a cross-platform MP3 player using 100% native
controls. In our XML file we used conditional attributes to display the Toolbar control
only on iOS, while for Android we set an open event on the window and took care of
configuring the ActionBar in our controller. We also saw how conditional operators can be
added to stylesheets and used to specify different styling properties to our window. Inside
our controller we assigned all the actual functionality, from establishing the songs to play,
to handling button clicks and playing songs with Titaniums cross-platform sound player.
Even when were merely scratching the surface, you can see with this small project how
Alloy allows you to use a web development paradigm to achieve native user interface,
performance and functionalities from a single code-base.

2.4 Adding themes to your apps


Alloy Themes take the concept of separating visual layout and functionality even further
than the MVC paradigm can. Alloy Themes are not Appceleratorprovided themes you add
to your apps, but rather a powerful feature that lets you create simple code bundles to
change your apps colors, graphics and even positioning of elements, without touching a
single line of JavaScript source code.
In this section well make changes to our MP3 Player to implement theme functionalities,
providing the same user experience and reusing all the code, but implementing different
UI. This is ideal in scenarios where the person writing the code is not the same as the one
building the UI.
Implementing themes allows you to properly distribute work across your development
team, letting the people working on user interface make changes to apps without touching,
and potentially breaking the JavaScript code. Themes provide complete code-UI
independency, so you can build apps that are easily customized for different situations or
even different clients.
In our original scenario our app had the Golden Gate Bridge as a background, but what if
we now want to use this same app for a different client, and that client requires a different
background? What if we want to have the buttons in a different area of the screen? That
sounds like a different app, right? Well, not really - this is the same app only using a
different theme.
Using themes could become an important component in your strategy to keep your code
organized and separating responsibilities within your development team. Lets look at how
we can easily make our app theme-aware.
When we built our MP3 Player app, we added our graphical assets and our songs folder to
the assets folder, and we applied our app styling to the index.tss file as seen on Figure
2.20.

Figure 2.20: Our current assets and


styles folders
Alloy Themes simply provide a way of bundling your apps assets and styles under a
single folder, and the name of this new folder is the name of our theme. Our original app,
the one with the Golden Gate Bridge in the background, had no theme because we didnt
plan for it. Now, if you know youll be using this app to sell it to other clients, a practice
known as white labeling, you need to easily change the look-and-feel of your app. In this
case, we name our theme goldengate, a name that easily tells you what it is about. Then
through the special config.json file we can tell Alloy which set of files to use when the app
is compiled. Lets go ahead and implement the goldengate theme to our app.

2.4.1 Setting up your app for themes


Well start by reorganizing our project so it works exactly the same as before, but this time
using themes. Go to your apps folder and create a new subfolder named themes as seen in
Figure 2.21. This folder needs to be created in the app folder, at the same level of assets,
controllers, views, etc., otherwise Alloy will not be able to find it.

Figure 2.21: Add theme folder(s)


Then inside this folder create a subfolder named goldengate, which will hold our current
set of assets and styles. Create new assets and styles folders inside the goldengate
subfolder and move the original files into this new folder as seen on Figure 2.22. The
name of the theme folder is the name of your theme and when referring to it you should
keep in mind that it is case-sensitive.

Figure 2.22: Add assets and styles to your theme(s)


Notice that we are leaving our original assets and styles folders empty. Alloy will not
complain about it because once we configure our app to use our goldengate theme, these
two folders will not be used for now. Later in this chapter well see how these two folders
could be used to override certain parts of our themes.
As a general suggestion, you should consider using themes even when youre not planning
on creating multiple versions of your app. This practice will help you to always stay
organized and make sure you keep your user interface definition completely independent
to the apps JavaScript code. Also, if you want to test out different ways of visualizing
your app, youd simply create a new theme, test it and make sure you like it and if not,
simply go back to the original one.
Now that we have created a theme and have moved our files into it, lets see how to tell
Alloy to use it.

2.4.2 Activating your theme


In your apps app folder youll find a file named config.json. As you remember from
Chapter 1 and as illustrated in Figure 2.23, Alloy precompiles and optimizes your app
before passing it over to the Titanium compiler.

Figure 2.23:
Alloys position in the Titanium development cycle
When the pre-compilation starts, Alloy reads this file, applies any settings and then
continues with the compilation process. One of these settings is the appss theme. By
default the config.json file is a template with no values.
{
global : {} , env : development : {} , env : test : {} , env : production : {} , os : android : {} , os : blackberry : {} , os : ios : {} , os
: mobileweb : {} ,
dependencies : {} }

Themes are added as a property inside the global object, so you simply add the theme to it.
{
global : {
theme : goldengate },
env : development : {} , env : test : {} ,
env : production : {} , os : android : {} ,
os : blackberry : {} , os : ios : {} ,
os : mobileweb : {} , dependencies : {}
}

By setting this value youve instructed Alloy to look for the styles and asset folder inside
the goldengate folder.
Config.json
The Config.json file provides a Global object, which besides being used to configure your
apps theme, it can be used to store any value you want to change from the outside of your
app. Moreover, it gives you a way to set said values with the granularity required by
modern apps.
{

global : { host : http :// defaultserver . com }, env : development : { host : http :// developmentserver . com }, env : test : { host
: http :// testserver . com }, env : production : { host : http :// productionserver . com }, os : ios : { host : http :// appleserver . com
},
os : android : {
host : http :// googleserver . com },
dependencies : {}
}

The values for this file are available to you by code by using the Alloy object Alloy.CFG.
In the example above the value for host will be available to your app as Alloy.CFG.host.
This value will be different depending on your deploy target. That is, if you compile your
app for iOS, Alloy.CFG.host will hold http://appleserver.com, and if you compile it for
Android it will hold http://googleserver.com. The dependencies property is used to specify
Widgets used by your app, explain in Chapter 4. The values prepended by env: will be
accessible depending on a flag named deploy-type, which you set via the Titanium CLI
and not accessible from Titanium Studio. For more information about the Titanium CLI
visit http://docs.appcelerator.com/titanium/3.0/#!/guide/ Titanium_CommandLine_Interface_Reference-section-35619828_ TitaniumCommandLineInterfaceReference-Build and for more information about the Alloy CFG property
you can visit http: //docs.appcelerator.com/titanium/3.0/#!/api/Alloy-property-CFG
You can now run the app and youll see that the app is exactly as before, only now the
assets and styles are being grabbed from the /themes/goldengate folder, as instructed by
the theme property in config.json, in other words, youve effectively taken your styles and
assets and have placed them in its own container called goldengate. From there on out, the
customizing of your app is extremely easy, as itll only require creating a new theme and
applying the required customizations. Lets go ahead and create a new theme.

2.5 Creating new themes


Up to this point you know what themes are about, what they are for, how they are
structured and how to activate them. In this section well go through the steps of taking
our current MP3 Player app theme and derive from it a new theme that will make our app
look different by simply changing a single line in the config.json file.

2.5.1 Adding new themes to an existing application


Lets assume that we now need to use the same concept of our MP3 Player, but with a few
differences. Well change the position of the controls bar so it is on the top, change the
player button graphics, the background image and the color of the playing track for better
contrast against the new background. Figure 2.24 shows how it will look.

Figure 2.24: MP3


Player with new theme applied
The Figure above depicts the result of our new Theme. Notice that it now has a new
background image, the color of the song description is now blue and the controls are on
the top, with a blue background and different buttons. Well call this theme caribbean. To
begin implementing it, create a new folder named caribbean inside the existing themes
folder and copy the assets and style folder from the goldengate theme as a starting point
(Figure 2.25)

Figure 2.25: Adding additional


theme
Immediately youll notice that we have a problem; both themes have a hard-coded
background image named goldengate. Themes should be generic and graphical assets
should not be named by what they are, but what they do.
In order to make this app completely generic and independent across themes, we need to
change the name of this file to represent its function, which is to provide a background, so
well rename it to background.png. Then, open /styles/index.tss on both themes and
change the name of the image to reflect the new one as seen in Figure 2.26.

Figure 2.26:
Change backgroundImage in content class.
After doing this your app will use a background image named background.png regardless
of the theme youre using. Your theme is now generic and creating new themes will only
require you to provide different versions of the already existing and referenced images.
You could now open config.json and change the theme property to reflect the caribbean
theme, and youll see that the app has a different background. We still need to change
some colors and the position of the control bar, but this is easy because we dont have to
touch the code at all; everything will be done by simply changing graphical assets and
making some minor changes in the index.tss file.
Now open up /themes/caribbean/styles/index.tss, which is the stylesheet for the caribbean
theme. To put the controls bar on the top and change its background color, simply make
the changes shown in Figure 2.27.

Figure 2.27:
Change color and position of the controlsbar class
In Figure 2.27 were changing the controlsbar class to be positioned in top=0 instead of
bottom=0. Also were changing the gray color of #cacaca to the blue #255F89. Finally to
change the actual buttons, replace the files btnnext.png, btnpause.png, btnplay.png,
btnprev.png and btnstop.png located in /themes/Caribbean/assets for new images.
This is all you need to do. The power of Alloy themes have provided you with a way of
changing the complete look-and-feel of your app without actually touching a single line of
JavaScript code.
Now that you have created the new them, its just a matter of opening up your config.json
file and apply the theme:
global : {
theme : caribbean
}

After making this change, save the config.json file, run your app and youll see the app
rendered with the new theme.
2.6. Summary

2.5.2 Global themes and assets


There are times when even though youre using themes, you still want to keep common
assets and styles across all themes. Such an example could be a Twitter feed screen that
will look exactly the same across themes, because the branding of Twitter is not something
you should change. For scenarios like this, Alloy allows you to keep your assets and styles
folder at the root level of your app.
If you place assets in your app/assets folder, you simply reference them from your app as
you would with theme assets. Alloy will try to look for the asset inside your theme/assets
folder and after not finding it, will look for it in the global assets folder. This happens
automatically and you dont have to keep track of the folder in which the asset is stored.
For styles, Alloy has a special app.tss, which you can optionally create in app/styles. In
this file you place any classes and Ids that you want to keep global and independent from
themes. Just like with assets, you simply assign the class or id to your screen element,
Alloy will try to find it in the theme styles and after not finding it, will try to look for it in
app.tss. Well use this technique in Chapter 5, section 5.2.

2.6 Summary
In this chapter youve seen:
The MVC pattern, how it works for the web and how it works with Alloy

What Alloy does for you under the hood


How to plan the development of your app and develop a strategy for building mobile
user interfaces
How Alloy uses its trio of files: XML, TSS and JS
How to write Alloy XML files
How to apply styling to your XML files from TSS files
How to write Alloy controllers in JavaScript, adding functionalities to your app and
changing UI elements by code
The benefits of adding themes to your apps and how it helps in making changes to your
app without touching a single line of JavaScript code
How to theme-enable an existing app
How to activate your theme in the config.json file
How to create new themes
Alloy is Appcelerators MVC framework for Titanium. By using the MVC pattern, your
code is easier to write, easier to maintain and easier to scale. As opposed to Titanium
Classic, with Alloy you write your apps using a combination of XML, TSS (like CSS) and
JS files, separating UI, styling and functionalities.
Alloy not only helps you keep your code better organized, but it actually helps us to write
better JavaScript code. All the Alloy files are pre-compiled and optimized into Common
JS modules that then are sent to the Titanium compiler.
Building mobile apps start with the planning phase, where you think about the
functionalities required by the end product, and a strategy is built around the UI and
functional requirements. Our MP3 player app ends up having the same functionalities on
iOS and Android but by using platform-specific conditional code, were able to apply
small functional and usability difference that make the app behave the way it is expected
on every target platform.
Alloy themes provide you with a mechanism of keeping entirely different sets of assets in
different folders. With Alloy themes you can have a single app, and easily rebrand it for
different scenarios, ideal for white label apps. Theme folders not only hold graphics, but
your style files can be used to change colors, and even the size and positioning of screen
elements.
In chapter 3 well be working with Alloy Widgets and how they can be used to
encapsulate not only styling, but also functionalities that can be reused throughout your
apps.

Chapter 3

Alloy Widgets
This chapter covers:
Creating Alloy Widgets from scratch
Understanding the Widget file structure
Creating Alloy Widgets out of functionalities of an existing app
In chapter 2 we built an MP3 player and later we implemented Alloy themes to provide an
easy way of changing the look-and-feel of our app, without touching the JavaScript code.
In this chapter well explore Alloy Widgets. A Widget is a user-defined component that
can be added to an app. Each Widget can contain user interface elements along with new
functionality that is not already provided by Titanium.
For example, lets say you want to display photos in a grid format. You could write the
code using ImageViews with the techniques we saw in Chapter 2, but what if you need to
use this grid display in different parts of your app? The traditional way of going around
this is by simply copying and pasting the blocks of code onto different Alloy controllers.
The main problem with this approach is maintainability: if you need to make a change,
youll then have to go through your apps code to manually make the change.
With Alloy, you could build this grid display as a Widget, which will contain all the user
interface elements along with the required functionality. This Widget will get added to
your project as a dependency only once and when needed, you simply add it to your Alloy
view.
In this chapter well see how to create a simple Widget and well explore all its
components. Then, well go back to the MP3 Player app and well build the media player
functionalities as an Alloy Widget, effectively detaching all the media player code from
your main apps code.

3.1 Creating Widgets


To begin, lets create a simple empty widget and Ill go through its structure and explain
its components. Go ahead and create a new project in Titanium Studio like explained in
chapter 2. Once the new project wizard finishes, go to your Project Explorer, locate your
project and right-click on it. From the pop-up menu select New and then Alloy Widget as
shown in Figure 3.1.

Figure 3.1: Create a


new Alloy Widget
This menu option will invoke Titanium Studios internal Widget creation process. The
next screen will prompt you for the widget name (Figure 3.2).

Figure 3.2: Enter


Widget name
Widgets can also be created from the Terminal/Command Window using the Alloy CLI
(Command-Line Interface). To do so, open a terminal/command window, navigate to your
apps folder and type: alloy generate widget com.companyname.widgetid. For more
information about the Alloy CLI, please refer to
http://docs.appcelerator.com/titanium/3.0/#! /guide/Alloy_CommandLine_Interface_Reference
Widget names can be any string, however, I suggest you follow the same convention you
use for App Ids, that is, using the reverse URI format, in this case, for illustration purposes
Im using com.companyname.widgetid. If for example I were building a Widget that
creates a list of icons, Id probably call it something like iconlist, making my Widget
name com.alcoapps.iconlist. This format not only will provide better organization of your
own widgets across projects, but as youll see later in this chapter it will help in
discoverability when you decide to use community-developed widgets or share your own

with other developers. After you hit OK, Titanium Studio will open for you the
widget.json file and have created a folder structure. Lets see what Alloy built for us.

3.1.1 Widget structure


The first thing to notice about Alloy Widgets is that they have their own definition file
named widget.json, automatically opened for you by Titanium Studio. This file holds all
the meta-data for this Widget.
{
description : ,
author : ,
version : 1.0 ,
copyright : Copyright ( c) 2012 ,
license : Public Domain ,
min - alloy - version : 1.0 ,
min - titanium - version :2.1 ,
tags : ,
platforms : android , blackberry , ios , mobileweb
id : com . companyname . widgetid , name : com . companyname . widgetid ,
}

Studio opens this file for you because its important that you dedicate a minute or two to
it. Youre building this widget now, so it is now that you have fresh on your mind what
this widget is for, plus other details, as seen in Table 6.1.
Property Id
Name
Description
Author
Version
Copyright
License
Min-alloy-version
Min-titanium-version
Tags
Platforms Description
Prefilled by Alloy. Holds the id of your Widget. Prefilled by Alloy with the same contents of the Id field. You should change this value to hold a more
humanfriendly name.
Here you should write the description of what youre widget is for. Think about what youd want to read if you go back to this widget 1 year from
today.
Your name
Version number of this widget.
Copyright. At the very least change the year to the current year.
License to use for this widget. Comes pre-filled with Public Domain. However, if youd like people to feel compelled to contribute code back to you, I
suggest you use MIT License. This is the one I always use: http://alco.mitlicense.org.
The minimum version of Alloy that will compile this widget. If you dont know, enter the version of Alloy youre currently using. The minimum
version of Titanium that will compile this app. If you dont know, enter the version of Titanium youre currently using. Tags that could lead people to
find your widget. A comma-separated list of the platforms this widget is designed for.

Table 3.1: Contents of the Widget.json file Now that you have added the meta-data for
your Widget, lets look at the folder structure, shown on Figure 3.3.

Figure 3.3: Widget folder structure


As you can see, if the widgets folder doesnt exits, Alloy will create for you. Then, Alloy
creates a subfolder with the id of your widget.
In Figure 3.3, the folder structure of a widget is very much like the folder structure of an
Alloy app, containing assets, controllers, styles and views. As opposed to creating actual
apps where your main app file is called index and for it you have corresponding XML,
TSS and JS files, in the case of widgets the files are called widget. The main difference is
that the widget view, widget.xml, instead of being a Window like index.xml, it starts with
a view, or with another UI component your widget may need like a TextField or Button.
The reason for this is that when you add your widget to your app, youre actually adding it
to an already existing Window. For example, if you open your widget.xml at this point
youll see this.
< Alloy >
< Label >I m the default widget </ Label >
</ Alloy >

Notice that just like your app views, Alloy XML files must start and end with the Alloy
tag. In this case, we have a Label between these tags. The default TSS file contains the
following:
Label : {
color : #000 ,
font : {
fontSize : 18 ,
fontWeight : bold },
height : Ti . UI . SIZE ,
width : Ti . UI . SIZE }

The TSS code above is the styling corresponding to the Label defined in widget.xml. This
styling is for the widget and the widget only, and will not conflict or overwrite the Label
styling in the app using the widget. Figure 3.4 shows the XML and TSS side-by-side.

Figure 3.4: Widget.xml


and Widget.tss side-by-side
Alas, even when our default assets folder is empty, these assets are for the widget, and will
not conflict with assets in the host app, as you can see in Figure 3.5.

Figure 3.5: Location of widget local assets and styles as compared with global ones
Finally, if you open widget.js youll see that the file is empty. The reason for this is
because our basic/default widget has no functionality, as it only shows a Label. Now, lets
see how to use this widget.

3.1.2 Using Widgets


Before you can use this widget, or any other widget for that matter, you must do two
things:
1. Physically add your widget to the apps folder structure
2. Tell your app that it depends on this widget
Titanium Studio does the first step for you. As you saw in Figure 3.3, Alloy created for
you a widgets folder to your app, and inside it added the folder containing your widgets
code. If this was an already created widget you were importing to your app, you simply
drop the widgets folder into the app/widgets folder.

The second step, where you tell the app that you want to use this widget, takes place in the
config.json file we saw in the previous chapter, which is located in /app. The last property
in this file is dependencies. This property holds list of widgets to be used by your app.
For each widget you have to specify its name, which is the name of the folder inside
widgets (and the id specified in widget.json), and the version to use (or an asterisk to
specify that you dont care about the version), which you specified in widget.json and was
described in Table 3.1. Titanium Studio does this step for you every time you create a
widget using the New Widget Wizard described above. For all other widget youll have
to open the file and add the entry by hand. At this point your config.json file looks like
this.
{
global : {} ,
env : development : {} ,
env : test : {} ,
env : production : {} ,
os : android : {} ,
os : blackberry : {} ,
os : ios : {} ,
os : mobileweb : {} ,
dependencies : {
com . companyname . widgetid : 1.0 }
}

Make sure you pay special attention to the versioning of your widget. The basic concept
behind Widgets is reusability, so by definition youll have multiple apps using the same
code. As you make changes to your widget you should increment its version number.
Also, you could create a README.md file inside your main widget folder and use it to
write the features of this particular version.
Now that your app knows youre using a widget, and your widget is properly stored inside
the widgets folder, were ready to use in in our app views. We do this using the special
Alloy Widget tag.
The <Widget >tag has two attributes:
src : Specifies the name of the widget id to use
< Widget src = com . companyname . widgetid id = myfirstwidget / >

id : A name you want to give to this widget in order to reference it by code. This Id must
be unique across your view.
To insert this Widget into your current app, open up your index.xml file and add the
Widget tag to it.
< Alloy >
< Window class = container >
< Widget src = com . companyname . widgetid id = widgetid / > </ Window >
</ Alloy >

Once youve added the widget tag to your view, save everything and run your app. The
results will your widget shown in the center of the screen as shown in Figure 3.6.

Figure 3.6: Testing


your basic/default widget in iOS and Android
Youve just created your first Widget, which though simple, illustrates the possibilities of
building external components that can be added to any of your apps. In section 3.2 well
go beyond the basics and build a full-featured widget with UI elements and exposed
methods and properties.
Widgets are used primarily to solve one of three problems:
To normalize code When the implementation of a certain feature is dramatically
different across platforms, a Widget can normalize the implementation into a simple call,
and have the Widget take care of the implementation complexities. As an example you can
take a look at the SocialShare Widget located at https://github.com/ricardoalcocer/
socialshare/tree/master/app/widgets/com.alcoapps.socialshare
As module wrappers Native modules are implemented in your controller. You can
however create Widgets that expose user-defined tags, making modules available as XML
tags. An example of this is the ViewPager module at http://fokkezb.nl/2014/10/17/alloyviewpager-widget/
To extend Titanium built-in APIs If theres a Titanium tag youd like to add more
features to, a Widget is an excellent mechanism. An example of this use-case is the remote
image widget located at https:// github.com/ulizama/com.baboonmedia.remoteimage,
which expands on the ImageView, providing remote image functionality and data caching.

3.1.3 Sharing and finding pre-built Widgets


One of the biggest benefits of using Alloy Widgets is that they can be shared. In fact,
chances are that the feature or functionality you need for your app has already been built
and made available from a member of the Titanium user community. The main places for
finding widgets are:
Gitt.io : Gittio is a website and command-line driven package manager that crawls and
collects Alloy widgets from Github. The website is fully automated, so many widgets may
not have instructions and youll have to figure them out by yourself by reading the code.

At the time of this writing, Gitt.io is the de-facto package manager for Appcelerator.
Github : Many people build widgets for their own projects and upload them to Github.
Theyre not that easy to find but theres many.
TitaniumControls.com : Similar to Gitt.io but manually curated with actual screenshots
of the Widget in use.

3.2 Building your first Widget


In this section well create a widget for the MP3 Player app from Chapter 2. Figure 3.7
illustrates the objective of our widget.

Figure 3.7: Widget


detached from host app
When you build Alloy widgets, in essence what you want to accomplish is to encapsulate
pieces of your UI and its related functionalities, into a reusable package. In our MP3
Player app, the audio playing functionality along with the UI to interact with the audio
will be our Widget. This will effectively detach the actual controls bar from the host
app, allowing you to insert the playing functionality into any Alloy app you build.
You could open up the app for modifying, or you could duplicate your project to keep both
versions. Titanium Studio has no option for duplicating projects, but its as easy as
creating a new Alloy project as before, and then copying the /app folder from your
previous app and replacing the newly created project.
Once you have your new project ready, create a new widget by right-clicking in your
project in the Project Explorer just as before (Figure 3.8).

Figure 3.8: Create


new Alloy Widget
If you run your app at this point you will see nothing new. This is because your app has a
widget, and the widget has been included as a dependency in your config.json, but you
havent referenced your widget in any of your views. Before we add it though, lets start
by moving the UI part from the existing app into the widget.

3.2.1 Implementing the UI


Its always easier to work with the visual part, so well begin with the reimplementation of
the UI, this time as a widget. If you open your apps index.xml, youll see that all of the UI
is implemented there. Figure 3.9 shows the exact portion of the code that we need to take
out of index.xml and move to your widgets view code.

Figure 3.9: Code to move from index.xml to the widget.xml


Cut this portion from index.xml, open up widget.xml and paste the contents onto that file,
as seen in Figure 3.10.

Figure 3.10:
Transferring view code from app to Widget
While at this, lets also go ahead and add the Widget tag to index.xml, leaving us with the
code in listing 3.1.
Listing 3.1: Index.xml
< Alloy >
< Window class = container
< Toolbar class = toolbar < Items >
< FlexSpace / >
< Label id = windowtitle / >
< FlexSpace / >
</ Items >
</ Toolbar >
< View class = content >
< Label id = songtitle class = songtitle > </ Label > < Widget src = com . alcoapps . musicplayer id = musicplayer / > </ View >
</ Window >
</ Alloy >
onOpen = doopen > platform = ios >

As you can see in listing 3.1 we are assigning musicplayer as the id for our Widget. Later
on youll see that in our controller (index.js) well be able to speak to the Widget using
the syntax $.musicplayer, just as any Titanium built-in UI component.
Going back to the code we moved, illustrated in Figure 3.10, youll see that we didnt only
move user interface elements, but also styling (referenced via Ids and Classes), and
behavior (referenced via onTouchStart and onTouchEnd events). We also need to move the
styling from the host app into the Widget.
To transfer the styling from the app to the widget, open index.tss and locate the styles that
are being used by the code we just transferred. To know exactly what to move, simply
identify anything that is either a class or an Id, as seen in Figure 3.11.

Figure 3.11:
Identifying classes and ids
Cut the code block that contains these classes and Ids from index.tss and transfer them to

widget.tss as seen in Figure 3.12.

Figure 3.12:
Transferring style code from app to Widget
The WPath Function
You may have noticed in Figure 3.12 that .btnprev, .btnplay and .btnnext are all
referencing images with absolute paths. This means that Titanium will look for these
images in the /app/assets, which is the root folder of your app. But we dont want that
because this is a Widget, and the Widget should use its own assets. To fix this, Alloy
provides a built-in function called WPATH. The WPATH function receives a name of an
asset, and simply returns the correct path in the context of this widget. The WPATH
function can be used from style sheets and controllers, and as a rule of thumb, every time
youre referring to an asset from within a Widget, make sure you use it to get the correct
location. Go ahead and change these three references to use the WPATH function as
shown below.
. btnprev :{
image : WPATH ( btnprev . png )
}
. btnplay :{
image : WPATH ( btnplay . png )
}
. btnnext :{
image : WPATH ( btnnext . png )
}

This takes care of the user interface and styling. Next up, lets look at the steps required to
move the functionality of our app onto the Widget.

3.2.2 Implementing functionality


When you add the functionality of your Widget, youre building a reusable component, so
the way you build your implementation is important. Whats more, youre in control, so
you can build this implementation any way you want.
In our Media Player Widget, all media playing functions need to be moved from the app to
the actual widget. Figure 3.13 shows the methods that need to be in our Widget in order
for it to be self-contained.

Figure 3.13:
Methods that belong to the Widget
All these functions are currently in index.js, but should belong inside the Widget. From
index.js we want to specify the songs to play. We also have to build a mechanism for the
Widget to write back to the apps screen. As you remember, our MP3 Player has a label in
the center of the screen displaying the song being currently played. This label will not be
part of the Widget, so we need to make sure the Widget can update that label as the player
moves through songs. Before we move the code to the Widget, lets have a look at listing
3.2 showing how much cleaner our apps index.js will look. Listing 3.2: index.js
$. musicplayer . setSongs ([
{ filename : / songs / file1 . mp3 , filetitle : This is song
1 } ,
{ filename : / songs / file2 . mp3 , filetitle : This is song
2 } ,
{ filename : / songs / file3 . mp3 , filetitle : This is song
3 }
]
);
$. musicplayer . setSongLabel ($. songtitle );
var thisWin =$. index ;
var winTitle = Media Player ;
function doopen ( evt ){
if ( OS_ANDROID ){
thisWin . title = winTitle ;
} else {
$. windowtitle . text = winTitle ;
}
$. musicplayer . updateScreen () ; }
$. index . open () ;

As you can see, our index.js looks much cleaner now that we have removed all media
playing functionality. Now lets see how to implement these features in our widgets
controller.
We start our Widget.js by initializing the variables well be using:
var songs , songLabel = null ;
var currentSong =0;

var audioPlayer = Ti . Media . createSound () ;

The code above is very similar to what we used in our previous version. The only
difference is that were initializing songs as null because at this point we dont know
which songs are to be played, and we have a new variable named songLabel, which will
be used to hold a reference to the label to be updated every time the player changes.
You can go ahead and move all the player methods unchanged, that is: prevdown, prevup,
nextdown, nextup, playdown, playup, playsong, stopplayer, moveback, moveforward and
updateScreen. Out of these methods we only need to change two of them: playup and
updateScreen. Playup needs to be updated to use the WPATH function as seen below.
function playup ( evt ){
evt . source . opacity =1;
if (! audioPlayer . isPlaying () ){
evt . source . image = WPATH ( btnstop . png ) ; playsong () ;
} else {
evt . source . image = WPATH ( btnplay . png ) ; stopplayer () ;
}
}

UpdateScreen needs to change so its updating the new variable that points to the outside
label. The change is simple go from this:
function updateScreen () {
$. songtitle . text = songs [ currentSong ]. filetitle ;
}

to this
function updateScreen () {
songLabel . text = songs [ currentSong ]. filetitle ;
}

The only difference is that we changed the object were assigning the filetitle to. In the
original version we were using $.songtitle, which is the Id of the Label inside index.xml.
We no longer have direct access to this object because were working from the widget, so
we created the variable songLabel to become a bridge to this label. Now we only have
three things left to do:
Establish the bridge between songLabel and $.songtitle
Receive the songs array from the host app
Allow the updateScreen method to be called from the outside
For these three well be using the special CommonJS exports object. Since with Alloy
everything is effectively becoming optimized CommonJS modules, we have access to the
exports object, which in turn will allow us to expose methods and properties to our host
app.
To create the bridge between $.songtitle and songLabel, we simply export a function that
will receive the external Label object and will assign it to our internal variable.
exports . setSongLabel = function ( args ) {
songLabel = args ;

You saw this function being called in listing 3.2 as


$.musicplayer.setSongLabel($.songtitle);
When you call this function from index.xml, the $.songtitle object will be

assigned to the songLabel variable locally in our Widget.


Next, to receive the songs array we use a similar technique.
exports . setSongs = function ( args ){
songs = args ;
}

You saw this being called in listing 3.2 as


$. musicplayer . setSongs ([
{ filename : / songs / file1 . mp3 , filetitle : This is song
1 } ,
{ filename : / songs / file2 . mp3 , filetitle : This is song
2 } ,
{ filename : / songs / file3 . mp3 , filetitle : This is song
3 }
]
);

When you call this function from index.xml, the songs array will be assigned to the local
songs variable.
Finally, updateScreen exists inside our Widgets controller and we want to expose it as-is,
so we use this syntax.
exports . updateScreen = updateScreen ;

When you call the updateScreen function from index.xml it will be directly calling the
updateScreen function inside the widget.
This completes the implementation of the Widgets functionality. Below youll find the
full listing.
Listing 3.3: Widget.js
var songs , songLabel = null ;
var currentSong =0;
var audioPlayer = Ti . Media . createSound () ;
function prevdown ( evt ){ evt . source . opacity =.5;
}
function nextdown ( evt ) { evt . source . opacity =.5;
}
function prevup ( evt ){ evt . source . opacity =1; moveback () ;
function nextup ( evt ){ evt . source . opacity =1; moveforward () ;
}
function playdown ( evt ) { evt . source . opacity =.5;
}
function playup ( evt ){
evt . source . opacity =1;
if (! audioPlayer . isPlaying () ){
evt . source . image = WPATH ( btnstop . png ) ; playsong () ;
} else {
evt . source . image = WPATH ( btnplay . png ) ; stopplayer () ;
}
}
function playsong ( evt ) {
audioPlayer . url = songs [ currentSong ]. filename ; audioPlayer . play () ;
}
function stopplayer () { audioPlayer . stop () ; audioPlayer . release () ;
}
function moveback () {
if ( currentSong > 0) {
currentSong - -;
if ( audioPlayer . isPlaying () ) {
stopplayer () ;
playsong () ;
}

updateScreen () ;
}
}
if ( audioPlayer . isPlaying () ) { stopplayer () ;
playsong () ;
}
updateScreen () ;
}
}
function moveforward () {
if ( currentSong < songs . length -1) { currentSong ++;
function updateScreen () {
songLabel . text = songs [ currentSong ]. filetitle ;
}
exports . setSongs = function ( args ){ songs = args ;
}
exports . setSongLabel = function ( args ) { songLabel = args ;
}
exports . updateScreen = updateScreen ;

Our widget is complete and we have successfully detached the media player controls,
along with all functionality, to an external component that simplifies our code and adds a
great deal of flexibility. You can now run your app and see that it works just as before.
You probably have noticed that we also introduced a new problem. If you try to switch
themes now, youll see they work for the app but not for the Widget. The Widget has all its
assets stored locally and they are not aware of the change in themes. Lets look at how to
add theming functionality to our Widget.

3.2.3 Adding themes to Widgets


Adding themes to Widgets is easy and only takes a few minutes. Theres an additional
folder structure youll have to add to your themes folder, shown in Figure 3.14.

Figure 3.14: Folder structure with Widget themes


The steps you need to follow at this point are:

1. Create a widgets folder inside each theme


2. Inside this folder, add one folder for each widget youre using and wish to provide
themes for, in this case com.alcoapps.musicplayer 3. Inside each widget folder create an
assets and styles folder 4. Move the contents of the styles and assets folder you have in
your widget onto this this new structure
As a result, your actual widget folder has now empty assets and styles folder because these
will be used from inside the widget theme. From now on, when you specify a theme inside
config.json, Alloy will use the apps assets and styles from the theme folder, and the
widget assets and styles from the widget folder inside the selected theme.
You can now run your app and change themes, and see how everything works just as
before, but you have a much more organized and reusable architecture. Your MP3 Player
app is now complete with theme functionality and all of the media playing functions have
been detached from the app, creating a self-contained, reusable and themeable external
component.
3.3. Summary

3.3 Summary
In this chapter youve seen:
How to create Alloy Widgets from scratch
Where to obtain user-created Widgets
How to take functionalities of an existing app and encapsulate as an Alloy Widget.
How to add themes to your Widgets
Widgets are one of Alloys most powerful features, something you dont find in any other
cross-platform mobile development tool. Not everything should be built as a widget, but
as you progress in your development of cross-platform apps youll be able to identify
pieces of your code that could be reusable across apps, making your code cleaner and
easier to maintain.

Part II

Advanced functionality

Chapter 4

Tabs and Advanced Android


Customization
This chapter covers:
Building a tab-based app
Working with images for different screen sizes and densities
Adding support for multiple languages
Using Androids built-in theme system
In this chapter well start building out first full-blown app. This app in itself is not really
difficult, but combines many different features such as Tabs, multilanguage support and
advanced Android customization. Every app requires a solid foundation to build on top of,
and thats exactly what well do here. Theres a lot to explain, so this chapter will cover
the creation of the crossplatform tab architecture, multi-language support and Android
themes, leaving us with a nice looking scaffolding for our app. The rest of the features will
be covered in Chapter 5 and 6. Its a pretty cool app that youll be able to use as-is, modify
to fit your needs, or simply grab pieces and ideas, and use them in other apps. Lets get to
it.

4.1 What well build


The app well build in this chapter is an app for a Conference which I call Alloy
Conference, for which you can see the main screen in Figure 4.1.

Figure 4.1: Alloy


Conference app running on iOS 7 and Android 4.4
This app, as youll see, is a well-rounded app that essentially covers the most important
aspects of a typical app. Throughout the example well see different Alloy features used in
a practical context, such as:
This Chapter
Building a tab-based app
Special iOS 8 UI features
Advanced Android ActionBar features
Native cross-platform UI and UX
Using Androids build-in theme system
Multi-language support
Chapter 5
Using third-party native modules
Using TableViews
Opening windows and passing data to them
Accessing the file system
Using Alloy models and SQLite databases
Using Alloy platform-specific folders
Chapter 6
Using ListViews
Web services and JSON parsing
Device features like opening web pages, opening other apps and initiating phone calls
In the process, Ill also guide you through the decision-making process used to
successfully build a true cross-platform app that looks, feels and performs as an app built

directly using Objective-C or Java, but everything from a single well-organized and
maintainable codebase.
When you run this app on a device, theyll be no way of telling that it was built using a
native framework, and thats the ultimate goal. This app will be optimized for handheld
devices, that is iPhone/iPod Touch and Android Phones. Although the app will run on
iPads and Android tablets, no effort will be made to make the screen adjust to large
screens. I will however give you tips on how you can easily make these adjustments.
In this chapter, as well as chapter 5 and 6, Im trying to explain the concepts as we run
into them, as opposed to giving you all the information and letting you figure out when its
needed. As a result, youll see that sometimes Ill ask you to go back to code that was
already written to make changes to it, but this is completely intentional.
Before we start building, lets look at the app requirements and features screen-by-screen.

4.1.1 Schedule Tab


The Schedule Tab will load the schedule in three different ways:
From JSON files stored in the phones file system
From a local SQLite Database
Using Backbone Models
I should mention at this point that although well be using structured databases and
Backbone models, the intention is not to create complex data models, but rather introduce
you to the three possible methodologies. As stated in previous chapters, this book is
primarily focused in UI/UX, and in general on the things that can be seen by the users. I
however will provide you links to explore more on both topics.
Since this example is for a three-day conference, well provide a method for switching
between days from within the same tab. This method differs between platforms: on iOS
well use a Segmented Control, which in Titanium is called TabbedBar. On Android well
use a ViewPager, which is not available in the Titanium core, but we can use through a
third-party open source native module. These two controls can be seen in Figure 4.2
holding the options labeled Day 1, Day 2 and Day 3. In both cases this will provide the
user with a way of moving through the days by clicking or swiping left and right.

Figure 4.2: The


Schedule Tab
You may be thinking why go through the trouble of using a native module when you could
use views to simulate the iOS TabbedBar on Android, and thats a valid question, for
which I have a valid answer. The answer simply is because we should always think about
our target platform and our target user. Each platform has its own way of displaying
things, sometimes they are very similar, sometimes slightly different, and some times
theres absolutely no equivalent. In this case we have an equivalent and we should use it.
Emulating user interface components is expensive to the phones rendering engine, and
even when you can successfully replicate certain functionality, the results, performancewise, could be unpredictable. You should emulate only when you have a strong and valid
reason for it.

4.1.2 Venue Tab


The Venue Tab will be used to provide details about the venue. The attendee will have the
possibility of learning about where the event is taking place, initiate a phone call or by
clicking on the address, open Google Maps to get directions (Figure 4.3).

Figure 4.3: The


Venue Tab
One thing to notice about this tab, that will also hold true for all other areas of the app, is
that the textual elements, that is the title shown on top of the image and the description of
the venue below it, will be displayed in the language chosen by the user.
Both iOS and Android provide the user with a way of setting their preferred language.
Apps like Twitter and Facebook, arguably two of the most important apps available for
mobile devices, change their user interface based on the phones language. This means
that if your phone is set to Spanish, apps display all their menus and screens in Spanish.
Titanium provides you with a built-in cross-platform mechanism for creating language
files in which you store all the messages used by your app. The app will then display the
correct text depending on the phones language. This app will use this mechanism and the
app will be available in both English and Spanish, and subsequently, in as many languages
as you want to create language files for.

4.1.3 Conversation Tab


This tab displays a list of Tweets for a given hashtag, fetched in real-time using the Twitter
API (Figure 4.4).

Figure 4.4: The


Conversation Tab
Using the Twitter API is not easy, but Ive componentized it in a way that its easy to use
and reuse.
Twitter returns the data in JSON format. Well parse the response and will extract the
users avatar, name and screen name, the actual tweet and the link to this tweet. Well
display it in a list very similar to the official Twitter app, and by clicking on each row,
well open the Twitter app if its installed, otherwise will open the web browser.

4.1.4 Videos Tab


This tab is very similar to the previous one, but this time pulling data for YouTube (Figure
4.5).

Figure 4.5: The


Videos Tab

YouTube also returns a JSON feed, but its much easier to connect to than Twitter. Well
extract from the feed the thumbnail, user, description, video link and duration, and well
display it in a table. By clicking on each row, well open the video on the YouTube app, or
on the browser if the app is not installed.
Now that you know what the end result should look like, lets go ahead and build this app
step-by-step. This app is full of features and interesting cross-platform decisions. I
promise itll be fun. Lets get started!

4.2 Setting up the apps architecture


To begin, create a new Titanium Mobile project as usual. When you reach the Project
Template window shown on Figure 4.6, select Default Alloy Project. You could select
the Two-tabbed Alloy Application, but well be deleting all its contents anyway.
Continue filling out the apps details like before. Youll be taken to the Titanium Studio
editor screen and youre ready to start.

Figure 4.6: Project


Template window

4.2.1 Setting up the Tabs container

Open up index.xml, which at this point contains the default window definition. For our
app well use a tab container, called in Titanium TabGroup. The TabGroup is a special
cross-platform object that holds a collection of Tabs. Tab objects themselves are
containers that hold Windows. The basic structure of a TabGroup is as follows.
< Alloy >
< TabGroup >
<Tab >
< Window >
</ Window >
</ Tab >
</ TabGroup >
</ Alloy >

You can have as many tabs as youd like. How they are rendered is different on iOS and
Android. On iOS, if Tabs dont fit on the screen, youll automatically get a More button
that will present a screen with links to all additional tabs. On Android, the tab bar is
scrollable, giving you access to all the tabs from the same screen. Our app has only 4 tabs,
so we wont run into any of these cases.
To create our four tabs, simply add additional tab objects inside the TabGroup tag:
< Alloy >
< TabGroup >
< Tab title = Schedule >
< Window title = Schedule backgroundColor =# FFFFFF > </ Window >
</ Tab >
< Tab title = Venue >
< Window title = Venue backgroundColor =# FFFFFF > </ Window >
</ Tab >
< Tab title = Conversation >
< Window title = Coversation backgroundColor =# FFFFFF > </ Window >
</ Tab >
< Tab title = Videos >
< Window title = Videos backgroundColor =# FFFFFF > </ Window >
</ Tab >
</ TabGroup >
</ Alloy >

If you save and run this project at this point your app will look like Figure 4.7).

Figure 4.7: Basic


representations of tabs on iOS and Android
Up to this point the app has its four tabs, but its far from what we need. Lets continue.
Its always a good idea to test often during your development. For this app youll see
yourself running the project, so you can see the effect of the changes made and, in case
something fails, you know what the problem is related to.
Our current code has the four windows defined in the same file, and while this works, its

not necessarily a good practice. As much as you can, youd want to keep each window as
an external component that is dynamically included into your files. For this Alloy provides
the Require tag. Lets go ahead and create our windows as independent files.
From the Project Explorer, right-click on any file and youll see a pop-up menu. Select
New and then Alloy Controller (Figure 4.8).

Figure 4.8: Create


new controller
Then, the New Controller window will open, prompting you for the name of the new
controller (Figure 4.9).

Figure 4.9: Add


controller name
The name of the controller is the name you wish to use for the XML, JS and TSS files.
Create the first one named schedule, and repeat the process for venue, conversation
and videos. This process if very similar to creating Widgets seen in the previous chapter.
In this case you dont need to type the name in reverse URI format; only write the file

name with no extension and Alloy will take care of the rest. You now need to repeat this
process for all your four XML files: schedule, venue, conversation and videos.
Controllers can also be created from the Terminal/Command line. Simply browse to your
project folder and type: alloy generate controller <controller name >, for example alloy
generate controller schedule, and Alloy will create the XML, TSS and JS files with the
given name in the appropriate folder.
You should now have all your controllers created as seen in Figure 4.10.

Figure 4.10: Project explorer with all controllers created


Having done this, we are ready to require them from our index.xml, which is as easy as
replacing the Window tags with the Require tag.
This Require tag has two attributes: SRC is used to specify the source, which is the actual
name of the file. ID is used to give it a unique name to reference them. These files are
external to index.xml, so once required, youll be able to access all of their components by
using this ID, just as if they actually were part of index.xml. Well see this in context
shorty. Your modified index.xml is now as follows.
< Alloy >
< TabGroup >
< Tab title = Schedule >
< Require src = schedule id = scheduleTab / >
</ Tab >
< Tab title = Venue >
< Require src = venue id = venueTab / >
</ Tab >
< Tab title = Conversation >
< Require src = conversation id = conversationTab / >
</ Tab >
< Tab title = Videos >
< Require src = videos id = videosTab / >
</ Tab >
</ TabGroup >
</ Alloy >

By default, controllers created by Alloy are Views. If you open, for example
conversation.xml, you can see it for yourself:

< Alloy >


< View class = container >
</ View >
</ Alloy >

If you run the project now youll get the following error.
[ ERROR ] Invalid Tab child Alloy . Require
[ ERROR ] Tab must have only one child element , which must be a Window
[ ERROR ] Alloy compiler failed

The problem is that youre actually inserting a View inside a Tab. The Tab can only hold
Windows, so youll need to change your code to have a Window as its root element.
< Alloy >
< Window class = container >
</ Window >
</ Alloy >

We have are basic tab structure ready to begin styling. Before we do so, notice that were
assigning the title for each tab as a string. If you recall from the beginning of the chapter,
we want to make this app available in different languages. This means that we should not
add any text as a hard-coded string. We need learn about app internationalization.

4.2.2 Internationalization
App internationalization, also known as i18n (I and N the beginning and ending letters of
the word internationalization, and 18 the amount of letter in between), is the practice of
making your app available for international markets. The success of your app is
proportional to the amount of people using it, but its unrealistic to assume everyone
speaks English (or any other language for that matter).
Titanium gives you an easy-to-use, cross-platform mechanism to make your app available
in as many languages as youd like. The language however is not selected on the app
itself, but at the operating system level. If your app is available in Japanese and the users
phone is set to Japanese, your app will be displayed in Japanese.
This is achieved through the use of ISO 639-1 codes. These codes are standard two-letter
codes used to identify a language. Full list can be found at
http://wikipedia.org/wiki/List_of_ISO_639-1_codes. The code for English is en, so go
to your Project Explorer and create a folder structure like the one in Figure 4.11.

Figure 4.11: Structure of


internationalization folder
Create a file named strings.xml inside your en folder. The format of this file is a simple

XML file with a root resources tag, and entries enclosed in a string tag. Create app title,
tab1 title, tab2 title, tab3 title and tab4 title as seen below. Every time we need to provide a
textual message on the app, we simply come to this file (or files) and create an entry for
that text.
< resources > < string < string < string < string < string
</ resources > name = app_title > The Alloy Conference </ string > name = tab1_title > Schedule </ string >
name = tab2_title > Venue </ string >
name = tab3_title > Conversation </ string > name = tab4_title > Videos </ string >

To access these entries Titanium provides the Ti.Locale namespace, which has a method
called getString, so if youd like to get the value for app title above, you simply call:
var app_title = Ti . Locale . getString ( app_title , The Alloy Conference ) ;

You can also use its shorthand version, L:


var app_title = L( app_title , The Alloy Conference ) ;

The first argument is the name of the string inside your string file. The second argument,
which is optional, is the default value to return in case the string doesnt exist in the file. In
both of these examples the result is the localized value of the string app title stored in the
app title variable. The function can be used from JavaScript controllers, TSS stylesheets or
XML views. Through the chapter well be using all three.
Titanium saves and caches your localized strings. For this reason there may be moments
when you have added a new string to the language file but it doesnt reflect on your app.
To fix this, go to Project >Clean to force Titanium to rebuild the whole project the next
time you run it. Clean can also be performed from the Terminal/Command Line by typing:
ti clean
Now that we have our Tab names as localized strings, lets start styling our TabGroup. Go
ahead and add IDs to each Tab in index.xml (tab1, tab2, tab3 and tab4) and the
corresponding entry in the Stylesheet. Inside the stylesheet use the L function to fetch the
localized string as shown in Figure 4.12.

Figure 4.12:
Relationship between index.xml, index.tss and language file
Now your code has a good modular base to build on top of and your app will be properly
organized. Now its time to prettify it. Lets start with iOS because as youll see in section
4.2.4, customizing colors in Android is extremely easy.

4.2.3 Tab Icons


If we look at the design of our app, tabs are presented differently on iOS and Android

(Figure 4.13).

Figure 4.13: iOS


tabs compared to Android tabs
On iOS, the native Tab Bar is anchored to the bottom, icons have a caption underneath and
are by default displayed in a tone of gray with a highlighted color (called Tint Color) when
selected. This is the native behavior you can see in any native iOS app.
On Android, the native Tab Bar is anchored to the top, right underneath the ActionBar.
There are more options as well: they can have only texxt, text and icon, or icon only,
which is the case of the screenshot above. The selected tab on Android is not highlighted
like in iOS, but rather, it shows a thin line of a slightly darker color. This is the native way
of displaying tabs on Android.
The Tab icons can be created with your favorite image manipulation program, or you can
get them from icon packs that can be found on the Internet. What you need to keep in
mind is the size of the images, which differs across platforms. Figure 4.14 shows a
diagram with the required image sizes for iOS (retina and non-retina) and Android extraextra high-resolution devices.

Figure 4.14: Tab Icon sizes


On Android, the extra-extra high-resolution image is 96x96, leaving a transparent gutter of
at least 10 pixels. From this image you derive images for additional Android screen sizes
described in the sidebar. In both cases, I suggest you leave a small gutter around the
image, so your images stay nice and centered and not too close together.
Android screen densities demystified
A common complaint by Android developers is how difficult it is to create graphical assets
that will render properly in the large array of Android screen sizes and densities. However,
its not as difficult as it sounds. Android has a built-in folder structure in which you
deposit your images, and it will select the appropriate ones for the device in which your
app is running. These folders are res-ldpi, res-mdpi, res-hdpi, res-xhdpi and res-xxhpi,
referring to low density, medium density, high density, extra high density and extra-extra
high density respectively. Using Tab Icons as an example, the mdpi image is 32x32, which
Android considers the normal size for devices with screens 470x320. From this starting
point you can apply the following rules:

ldpi is 75% of the normal size (.75)


mdpi is 100%, the normal size
hdpi is 150% of the normal size (1.5)
xhdpi is 200% of the normal size (2)
xxhdpi is 300% of the normal size (3)
The number in parenthesis is the decimal representation of the percentage and its called
Logical Density Factor.
With this information, you can now calculate the right image size for xxhdpi, by
multiplying 32 (the normal size) by 3 (300%), and the result is 96x96. Do the same thing
with the rest of the sizes and youll end up with images properly sized for each different
screen density.
These files and folders live inside app/assets/android/images. If the folders are not already
there, simply create them and deposit the images inside of them. From code, you then
refer to the image as /image/<imagename > and Android will grab the corresponding
one, no need to do anything special.
In order to maintain the best image representation, its always better to scale down than to
scale up, so start by creating your xxhdpi image (96x96) and generate the rest by scaling
down to the appropriate sizes.
If at anytime you need to dynamically time, you can access the devices logical
Ti.Platform.displayCaps.logicalDensityFactor. This will return the decimal number
mentioned above, which you can then use to dynamically scale the image to the right size
for the device youre running on.
This is not a Titanium-specific behavior, but an Android one, and you can find more indepth information about supporting multiple Android screen sizes and densities at
http://developer.android.com/guide/practices/ screens_support.html.
scale any image at rundensity factor by calling
iOS is more standardized because, at the time of this writing, you only have three possible
screen resolutions: 1x (normal non-retina), 2x (retina) and 3x (iPhone 6 Plus). 1x are
around 30px and not larger than 48 x 32, 2x are around 60px and not larger than 96 x 64
and 3x are around 75px and not larger than 144 x 96. iOS has a special naming convention
for these images, which is appending @3x or @2x to the file name. For the schedule tab
where naming the image schedule.png for non-retina devices, and schedule@2x.png is the
retina version. The appended @2x simply means that this image is twice the size of the
one without @2x.
You can find the official Image Sizes and Types at https:
//developer.apple.com/library/ios/documentation/userexperience/
conceptual/mobilehig/IconMatrix.html
Drop these images in /app/assets/iphone/images (Figure 4.15), and from code you simply
refer to them by /images/<imagename >. The @2x or @3x is never used in code; iOS will
take care of using the correct one for the device in which your app is running. Just like
before, this is not a Titanium behavior but an iOS native one.

Figure 4.15: iOS Image Locations


Notice that youve created image folders inside the platform-specific folders
/app/assets/iphone (Figure 4.15) and /app/assets/android (Figure 4.16).

Figure 4.16:
Android Image Locations
When Titanium compiles your app, it will grab the images for the platform youre
building for, and will leave the rest behind, making sure that your iOS app doesnt carry
over assets designed for the Android version and vice-versa. In the case of Android, itll
grab all versions of your images and will use the right one depending of the device youre
app is running on.
Now that you have created the images and have stored them in the appropriate folder,
were ready to create our stylesheet (index.tss), shown below.
Listing 4.1: Index.tss
TabGroup [ platform = ios ]:{
tabsTintColor : #6 A9E68 ,
tintColor : # ffffff
}
# tab1 [ platform = ios ]:{
title :L( tab1_title ) , icon : images / schedule . png
}
# tab2 [ platform = ios ]:{
title :L( tab2_title ) , icon : images / venue . png
}
# tab3 [ platform = ios ]:{
title :L( tab3_title ) ,
icon : images / conversation . png

}
# tab4 [ platform = ios ]:{
title :L( tab4_title ) , icon : images / videos . png
}
# tab1 [ platform = android ]:{
icon :/ images / schedule . png
}
# tab2 [ platform = android ]:{ icon :/ images / venue . png
}
# tab3 [ platform = android ]:{
icon :/ images / conversation . png
}
# tab4 [ platform = android ]:{ icon :/ images / videos . png
}

You may need to clean your project after adding images to platform-specific folders
Were almost finished preparing the base structure for our app. One last thing well do
before getting into Android customization is to set the app title on the Android ActionBar,
shown in Figure 4.17.

Figure 4.17:
ActionBar Title
In Chapter 2 and 3 we simply set the window title and it was assigned to the ActionBar.
However, Ill use another method now, just to introduce you the advanced ActionBar
access.
Go ahead and open index.js and attach an event listener to the open event of our TabGroup
($.index). Inside this listener well grab a reference to the Android Activity, then a
reference to the actual ActionBar, and finally set the title directly to it.
$. index . addEventListener ( open , function ( evt ) {
if ( OS_ANDROID ){
var activity = evt . source . getActivity () ; var actionbar = activity . actionBar ;
actionbar . title = The Alloy Conference ;
}
})
$. index . open () ;

Activity is an Android concept, not a Titanium one, and to learn more about it please refer
to http://developer.android.com/reference/android/app/ Activity.html
You can run the app right now and your icons should be showing on both iOS and
Android, the iOS version with a green highlight on the selected Tab.
The icon in the ActionBar is the actual apps icon. You can however specify a different
one assigning it to actionbar.icon in the function above.
Now we need to get our Android version to parity with iOS by applying the appropriate
colors to the Tab Bar, and this is done using Androids native theming system.

4.2.4 Android Customization


Many Android visual controls cant be styled using TSS files or Titanium JavaScript code.

The reason for this is because Android has its own, very flexible way of creating themes
and styles for your apps. These themes however are applied to your app at build time
instead of runtime, so you have to bundle the theme with your app and then compile it.
Two such controls are the ActionBar and Android Tabs.
I wont get into details of how Android themes are structured because this is a complex
native Android concept. Ill however show you how you can quickly generate an
ActionBar Style and apply it to your Titanium app.
You can find information about the theme/styles file structure at http:
//developer.android.com/guide/topics/ui/themes.html
To create an ActionBar style for our app, head over to http://jgilfelt. github.io/androidactionbarstylegenerator. This website offers a free, web-based tool to configure the
different colors of your ActionBar Style, as you can see in Figure 4.18.
This online tool is part of a website called Android Assets Studio ( http:
//romannurik.github.io/AndroidAssetStudio/), which I suggest you visit often because it
can help you in generating many different Android-specific graphical assets and settings.
Fill out the fields as shown on Figure 4.18.

Figure 4.18:

Configure ActionBar Style


Name your theme GreenAb (Green ActionBar). Make sure you set compatibility to
AppCompat; this is the Android native library Titanium uses to provide an ActionBar with
backward compatibility. Then set your base theme to Dark. This will use a pre-defined
Android theme that assumes a dark background, so fonts will be white by default. For
the colors, use the following codes.
Action Bar Color: #6A9E68
Stacked Color: #6A9E68
Tab Indicator Color: #4B6D49
Popup Color: #6A9E68
Accent Color: #4B6D49
Action Mode Background Color: #FFFFFF
Action Mode Highlight Color: #4B6D49
Youll notice that as you change colors, the live preview changes automatically, which is a
great feature as otherwise you wont be able to see the effect until you compile your app.
If you look at the bottom of the page, youll see a list of graphical assets that the tool has
created for you (Figure 4.19), and thats precisely how Android changes the theme of your
app, by changing graphics.

Figure 4.19:
Download resources
Click on the Download Zip button, download this file and decompress it. Inside youll
find a res folder. Now go to your apps source code folder, and at the same level of your
tiapp.xml create a folder named platform and inside, one named android. Drop your
decompressed res folder onto this folder, as seen in Figure 4.20.

Figure 4.20: The /platform/android folder


Finally, you need to tell Titanium to use this Theme. Open your tiapp.xml file, scroll down

to the android section, and replace it with the following.


< android xmlns : android = http :// schemas . android . com / apk / res / android >
< manifest >
< application android : theme = @style / Theme . Greenab / >
<uses - sdk android : targetSdkVersion =19/ >
</ manifest >
</ android >

With these lines youre re-configuring your Android Manifest file (Androids main
configuration file), specifying that the app will use a custom theme named Greenab.
Figure 4.21 shows a comparison of our app with Androids default theme on the left and
our app with the custom GreenAB theme we just created.

Figure 4.21:
Comparison of default and custom Android theme
Before we finish, lets look at one last optional detail. Theres a thin line dividing the
ActionBar from the Tab Bar (Figure 4.22)

Figure 4.22:
ActionBar divider line
4.3. Summary
As mentioned before, these settings are applied to your app at build time, so theres no

bottomborder property. If youd like to remove this line, youll have to modify the
actual image used as background to your ActionBar. This particular image, in the case of
our GreenAb theme is called ab solid greenab.9.png, and can be found in your
platform/android/res folder as seen in Figure 4.23.

Figure 4.23:
ActionBar divider line
You can freely open this file in a bitmap editor and change the color of the bottom line to
match the color of the rest of the image. Just make sure you dont mess with the external
pixels of the image. These pixels are the 9-patch delimiters, used by Android to know the
portions of the image that are stretchable. You can find more information about 9-patch at
http: //developer.android.com/tools/help/draw9patch.html. Also notice that youll have to
change the mdpi, hdpi, xhdpi and xxhdpi versions of the image.
Now you can run your app again and see the changes. Our apps basic structure is now
finalized, so were ready to move to the next chapter and start adding content to the tabs.

4.3 Summary
In this chapter youve seen:
Building a tab-based app
Working with images for different screen sizes and densities
Adding support for multiple languages
Using Androids built-in theme system
We saw that while the TabGroup tag is cross-platform, tabs are rendered different on each
platform. We also saw that on Android we have the ActionBar, always displaying the
name of your app, while on iOS we have the title of the currently selected tab. Learn to
embrace these differences in order to achieve the best user experience possible for each
platform. Dont try to implement and ActionBar-like title bar on iOS, or try to emulate
iOS tabs on Android. Doing this will steer you away from native UI and UX, and in the
end will confuse your user. The end goal is to deliver the same functionalities on each
platform, but rendering the user interface in the way the platform dictates.

We now have a solid foundation for our app. In Chapter 5 well work on the schedule
tab, where well use native Android modules and local databases.

Chapter 5

TableView, third-party modules and


working with Local Data
This chapter covers:
Using third-party native modules
Using TableViews
Opening windows and passing data to them
Accessing the file system
Using Alloy models and SQLite databases
Using Alloy platform-specific folders
One of most important user interface elements available on mobile devices is the vertical
scrolling list. You use this component when youre searching for a contact on your phone,
or when your scrolling through your Facebook or Twitter feeds. In Titanium this
component is called TableView and in this chapter youll learn how to use it to display the
schedule of our conference app.
The data for the TableView shouldnt be hard-coded, so in this chapter youll also learn
how to create and utilize local databases. With Titanium data access can be implemented
in different ways, so well be implementing data access in three different ways: Persistent
App Properties, SQLite Databases and Alloy Models. As mentioned in the previous
chapter, although well be using structured databases and Backbone models, the intention
is not to create complex data models, but rather introduce you to the three possible
methodologies. This book is primarily focused in UI/UX, and in general on the things that
can be seen by the users. I however will provide you links to explore more on both topics.
Lastly well be using one of Titaniums most powerful features: native modules.
Throughout your Titanium development youll find yourself in situations where the
Titanium API is not exposing a specific feature or UI element. Luckily Titanium provides
a way for developers to expose these features themselves via native modules. We wont be
learning how to create modules. Modules are written using the native languages
(Objective-C for iOS and Java for Android) and require a deep understanding of
Titaniums internal architecture as well as the native SDKs. Well however learn where to
find native modules to use in our applications, and well use one in our conference app to
expose an Android component called ViewPager. Lets jump right in.

5.1 Third-party modules


The goal of Titanium is not to expose 100% of the native SDKs, but rather, expose the
most important and common features of the supported platforms, and make them available

through an easy-to-use cross-platform API. Appcelerator however offers native developers


with a robust framework that can be used to expand the Titanium API. Some examples of
available native modules are:
TiPebble Enables your iOS app to communicate with Pebble watches
(https://github.com/jbeuckm/TiPebble)
Android DrawerLayout Exposes Androids native slide-in menu (https:
//github.com/manumaticx/Ti.DrawerLayout)
ActionBarExtras Exposes several ActionBar features not available in the Titanium core
(https://github.com/ricardoalcocer/actionbarextras)
The Schedule tab is where our user will go to find out information about the different talks
of our conference. The conference is a three-day event, so were providing a simple way
for switching between days. In Figure 5.1 you can see a very special scenario. Well be
creating a tab page that will be displayed completely different on iOS and Android, and
for this reason, this tab is also the most complex of the four.

Figure 5.1: Platform-specific code is not re-usable, but the data and logic is. The decision
of displaying the data differently on iOS and Android is based on usability and overall
user behavior. In this example we want to provide three pages of data (the days) inside one
tab (the schedule). It so happens that on iOS and Android this type of scenario is handled
using different screen controls. Lets start with Android.
Although Titanium allows you to build your UI in any way you want and provide exactly
the same UI and UX across all target platforms, thats a conscious choice. The goal of a
cross-platform developer should always be to build an app with the greatest amount of
reusable code, but still deploy an app that is considered best in class in every platform its
running on. Code reusability is for actual programming logic and not necessarily for user
interface code.

5.1.1 Android view


For the Android version of this screen well be using a native Android component named
ViewPager. Youve probably used this control in many different Android stock apps, for
example the Google Play Store; it is very intuitive, providing a set of scrollable pages and
Android users already know how to use it (Figure 5.2).

Figure 5.2: How


the ViewPager works
This control however is not available as part of the Titanium API, so to use it we need to
get it as an external module.
Using native third-party modules
Titaniums goal is not to expose 100% of the capabilities of each mobile platform. For
features not included in the core SDK, Appcelerator provides developers with a
mechanism for creating Native Expansion Modules that bring additional functionalities to
Titanium. Most of these modules can be found in Appcelerators official marketplace at
http://marketplace.appcelerator.com. You can also find modules at
http://titaniumcontrols.com, http://gitt.io, or by simply running a search on Github. The
module well be using is found on Github at
https://github.com/ricardoalcocer/viewpager/tree/master/ dist. Download the file
com.navid.tabs-android-1.1.zip (or most recent build) and decompress it.
Modules provide a README.md file or /documentation folder with instructions on how
to use it
When modules are downloaded they come packaged in a ZIP archive. Decompress this
file and youll have a folder structure that starts with module. Drag this folder onto your
apps folder, at the same level of tiapp.xml as seen in Figure 5.3. The folder structure also
gives you details you need to tell Titanium that you wish to use this module.

Figure 5.3: Module folder structure


By using this ViewPager module, were limiting our Android app to newer Android
devices, so although Android apps built with Titanium could run on Android devices
running Android 2.x and up, this particular app is optimized for Android 4.0 and up.
Again, these are conscious decisions to be made in a case-by-case basis.
Open your tiapp.xml, scroll down to the modules section and replace it with the
following module declaration
< modules >
< module platform = android version =1.0 > com . navid . tabs </ module >
</ modules >

Copying the module to the modules folder is not enough. By adding this line, your app
now knows that it has a module to be loaded for your app. This is the process youll
follow every time you need to add a native module to your app. Id like to emphasize that
we have added a native Android module. This means that this will only work for Android.
Native modules are by definition platform-specific. Keep this in mind, as the features
provided by an Android module will not be available for iOS and vice-versa.
To make sure we only make the ViewPager available for Android, well use Alloys
platform-specific folders. Go ahead and create android and ios folders inside views,
and move schedule.xml to the android folder as seen in Figure 5.4. Do the same thing
with the controllers folder: create ios and android folders and move schedule.js to
the android folder. When your app is compiled, Alloy will grab the views and
controllers that correspond to the platform youre building for.

Figure 5.4: Platform folders inside Views


Now we can use these files and put any android-specific code in. Youll be doing this only
when you absolutely need to keep platform-specific code organized, and most likely this
happens when youre using native modules or some times to create your main app
container. This practice will make your code easy to write, debug and maintain. If at some
point youre facing problems with the Android version, you know youll find the code
inside the Android folder.
If you at this point build your app for Android, Alloy will use schedule.xml and
schedule.js inside these folders. If you on the other hand try to build for iOS, theres no
schedule.xml or schedule.js, so you will get an error when trying to require that file from
the TabGroup (where schedule.xml is referenced). Well get to iOS later. Lets continue
with the Android version.
For Android our schedule.js file will look listing 5.1.
Listing 5.1: schedule.js
var args = arguments [0] || {};
var tabs = require ( com . navid . tabs ) ;
var tabs = tabs . createPagerTabs ({
current : 0 ,
tab : {
indicatorColor
backgroundColor
alignment
shouldExpand
color
upperCase
},
views : [
{
: Alloy . Globals . viewPager . indicatorColor , : Alloy . Globals . viewPager . backgroundColor , : tabs . ALIGNMENT_LEFT ,
: true ,
: Alloy . Globals . viewPager . color ,
: Alloy . Globals . viewPager . upperCase {
title : L ( day2_caption ) ,
view : Alloy . createController ( day2 ) . getView () },
{
title : L ( day3_caption ) ,
view : Alloy . createController ( day3 ) . getView () }
]
}) ;
title : L ( day1_caption ) ,
view : Alloy . createController ( day1 ) . getView () },
$. schedule . add ( tabs );

First thing to notice is that Im grabbing the title of the tabs from the i18n file: make sure
you create entries for day1 caption, day2 caption and day3 caption. Besides this, there are
two things in this listing that require further explaining: the lines referring to
Alloy.Globals that allow you to create globally-accessible properties, and the lines
referring to Alloy.createController that allows you to include controllers inside other
controllers.
Making configuration global
In order to keep all our configuration and settings decoupled from the actual logic, well
use a special Alloy feature that allows us to create global settings in the alloy.js file. Inside
this file you can add settings that will be available to your app just before your actual app
is run. Alloy provides two objects: Alloy.Globals and Alloy.CFG, the former used for
basic global variables and the latter for configuration settings. Well add the following:

Alloy . Globals . viewPager = {


indicatorColor : #6 A9E68 ,
backgroundColor : # A1CC9F ,
color : #000000 ,
upperCase : true
}

In this code were creating a property named ViewPager inside Alloy.Globals. This object
can be modified from outside of our app, and accessible from code by calling
Alloy.Globals.viewPager.property name. From here on out, if we want to change any of
these settings, instead of going to schedule.js, we simply go to alloy.js. I know that
technically speaking the ViewPager colors are actually configuration, but for illustration
purposes Im storing these values as Globals. In Chapter 7 well see how to use
Alloy.CFG.
Inserting controllers dynamically
Controllers can be inserted into other controllers. As I mentioned earlier, when you create
a controller that is not the base of your window, you dont need to have a TabGroup of a
Window as your base tag; your controller could be any piece of code, like a View, a
Button, etc., that youd like to keep as a separate file in order to ensure reuse throughout
your code.
Go ahead and create three new controllers called day1, day2 and day3, and dont do
anything to them. These will be used to hold the contents of each days schedule and were
creating them as external files to ensure reusability across platforms.
In Listing 5.1 you can see how were inserting these views using the following syntax
shown in Figure 5.5.

Figure 5.5: Loading


controllers into your code
Controller name is the file name (without the file extension) of the controller youre
invoking. Controller arguments is an object you pass to the target controller, but more on
that later.
The code above effectively loads the controller. Then to turn it into a Titanium View, you
use the getView method like:
view = view . getView () ;

You can chain both calls (in fact this is the recommended way) in a single line like:
var view = Alloy . createController ( controller_name ,
controller_arguments ). getView () ;

In this example our controllers are simple. If your controllers have complex logic that
could generate errors, I suggest you wrap your Alloy.createController call in a Try/Catch
block
Your schedule.js for Android is ready, using the external ViewPager module, grabbing
configuration settings from alloy.js and inserting external views. Since the module is

instantiated from within the controller, theres no need for special XML tags. If you recall
from listing 5.1, once the tabs are created theyre inserted into the view with the line
$. schedule . add ( tabs );

The schedule.xml file is simple as it only needs to provide you with the $.schedule
container as follows.
< Alloy >
< Window id = schedule class = container layout = vertical > </ Window >
</ Alloy >

Finally, the schedule.tss up to this point simply holds the styles the $.schedule container,
as seen below.
. container [ platform = android ] : {
backgroundColor : # fff ,
barColor : #6 A9E68 ,
title : L ( tab1_title ) ,
orientationModes :[ Ti . UI . PORTRAIT , Ti . UI . LANDSCAPE_LEFT , Ti .
UI . LANDSCAPE_RIGHT ],
layout : vertical
}

Here we used another localized string so dont forget to add tab1 title to your i18n files.
Youre now ready to test the app and see how were doing. It should look like Figure 5.6.

Figure 5.6: The ViewPager successfully added to schedule.xml


Now that our Android version is ready, lets get our iOS version up to speed.

5.1.2 iOS view


As you recall from the beginning of the chapter, our goal is to have two platformspecific
containers, while maintaining code reusability for their contents, as seen in Figure 5.7.

Figure 5.7: Recap of our goal: Two platform-specific containers with common content
For our iOS container well use two different components. The first one is the TabbedBar,
which creates the strip of buttons on the top, shown in Figure 5.8. In the iOS SDK, this
control is called Segmented Control.

Figure 5.8:
TabbedBar and ScrollableView on iOS
For the actual containers well use a ScrollableView, a control to which you add as many
views as needed and allows you to scroll through them. Well then use event listeners to
synchronize the movement of the views with the actual buttons and vice versa.
To begin, just like before, create a controller named schedule, either through Studio or the
CLI. Make sure that just like before you move schedule.xml to /views/ios/schedule.xml
and schedule.js to /views/ios/schedule.js. Now, open the schedule.xml for iOS and lets
define our view, shown in listing 5.2.
Listing 5.2: /ios/schedule.xml
< Alloy >
< Window class = container >
< TabbedBar id = dayoptions platform = ios onClick = changeday >
< Labels >
< Label class = day1button / > < Label class = day1button / > < Label class = day2button / >
< Label class = day3button / > </ Labels >
</ TabbedBar >
< ScrollableView pageChange > < Require id = scrollableView onScroll =
src = day1 / > < Require src = day2 / >
< Require src = day3 / >
</ ScrollableView >
</ Window >
</ Alloy >

In the listing above we defined two event listeners. First we have an onClick for the
TabbedBar. This event will receive the ordinal of the button that was pressed and well use
this value to set the currentPage property of the ScrollableView. The second event is an
onScroll, which will give us the ordinal of the current page, which will use to set the
selected button. These two events effectively synchronize the TabbedBar and the
ScrollableView to work together as one. Listing 5.3 shows the implementation of these
two events in schedule.js.
I added the onScroll event just to show how to listen to scroll events and synchronize them
with the TabbedBar. Adding horizontal scrolling to the Segmented Control is entirely
optional

Listing 5.3: /ios/schedule.js var args = arguments [0] || {};


function changeday ( evt ){
$. scrollableView . currentPage = evt . source . index ; }
function pageChange ( evt ){
$. dayoptions . index = evt . source . currentPage ; }

Finally we need to complete the stylesheet, which we started with the Android version.
Simply merge the values in listing 5.4 with the ones we already added for the Android
version.
Listing 5.4: /styles/schedule.tss
. container [ platform = ios ] : { backgroundColor : # fff , barColor : #6 A9E68 , title : L ( tab1_title ) ,
orientationModes :[ Ti . UI . PORTRAIT , Ti . UI . LANDSCAPE_LEFT , Ti .
UI . LANDSCAPE_RIGHT , Ti . UI . UPSIDE_PORTRAIT ], layout : vertical ,
statusBarStyle : Titanium . UI . iPhone . StatusBar . LIGHT_CONTENT
}
# scrollableView :{
showPagingControl : false , scrollingEnabled : true
}
# dayoptions [ platform = ios ]:{ backgroundColor :#6 A9E68 , top :5 ,
bottom :5 ,
height :25 ,
width :200 ,
index :0
}
. day1button :{
title :L( day1_caption )
}
. day2button :{
title :L( day2_caption )
}
. day3button :{
title :L( day3_caption )
}

After performing these changes, go ahead and compile the app for iOS (shown in Figure
5.9) and youll see that we have it up to parity with the Android version.

Figure 5.9: App on iOS


Now that we have both iOS and Android up to speed, lets work on the contents of each
day tab.

5.2 Creating Table Views


The contents of Day 1, Day 2 and Day 3 are displayed using a vertical list as seen in
Figure 5.10. With Titanium, there are two ways of creating this type of list: with the
TableView and with the ListView. Ill explain the ListView later in chapter 6 and for these
screens Ill be using the TableView.

Figure 5.10: The TableView


Theres also a third way of creating vertical lists with a ScrollView (not to be confused
with the ScrollableView used before), and well use it later on this chapter. You can
explore more at http://docs.appcelerator.com/ titanium/3.0/#!/api/Titanium.UI.ScrollView
A TableView is essentially a UI construct that allows you to display elements in a vertical,
scrollable list. The main Titanium object is called TableView, and its children are
TableViewRows. TableViewRows are themselves containers to which you can add regular
UI elements.
TIP
Theres really no limit to the amount of rows you can add to a TableView. However, you
should be cautious and only show the amount of rows your user requires: if you have
5,000 rows in a database, you should never assume your user needs all of them. In such a
scenario you should provide a way of searching or filtering the data, so the rows are added
as the user requests them. Also, the TableView is not very efficient with complex rows,
such as those with many icons, graphics and remote data. The reason for this is purely

technical and for these cases you should use the ListView, which well explore in the
following chapter.
Creating a TableView is really straightforward. For example, to create a simple list with
the numbers from 1 to 5, youd write something like this.
< TableView >
< TableViewRow >
< Label >1 </ Label >
</ TableViewRow >
< TableViewRow >
< Label >2 </ Label >
</ TableViewRow >
< TableViewRow >
< Label >3 </ Label >
</ TableViewRow >
< TableViewRow >
< Label >4 </ Label >
</ TableViewRow >
< TableViewRow >
< Label >5 </ Label >
</ TableViewRow >
</ TableView >

A TableView is rarely hardcoded; most of the times youll be building your


TableView dynamically. This means that you really have to build the TableView
and the TableViewRow only once, and then youd write an automated process
to dynamically create the rows. Figure 5.11 shows the TableView row for our
conference schedule.

Figure 5.11: TableView and TableViewRow All rows are identical, the only change is their
content. Each row will be an actual container in which well create two columns. The left

column well use for the time and location, and the right column well use of the
description of the talk, as seen in Figure 5.12.

Figure 5.12: Layout of the TableViewRow


In order to visualize the TableView before we add the dynamic process that will fill out the
row, lets go ahead and build it with only one row. Open day1.xml and add the following
XML markup.
< Alloy >
< TableView id = day1table class = table >
< TableViewRow id = row class = row rowId = >
< View class = timecol >
< Label id = time class = timecaption >8 am -9 am </ Label > < Label id = location class = locationcaption > Main Room
</ Label >
</ View >
< View class = descriptioncol >
< Label id = talkname class = talkname > Building a conference app </ Label >
< Label id = speaker class = speaker > Ricardo Alcocer </ Label >
< Label id = talkdescription class = talkdescription >I this talk you ll learn how to build a conference app for iOS and Android using
Appcelerator </ Label > </ View >
</ TableViewRow >
</ TableView >
</ Alloy >

In Chapter 2, I mentioned that Alloy has a special file called app.tss, to which you can add
global styles that will be available to all your views. Since all three pages - Day 1, Day 2
and Day 3 - have exactly the same visual aspect, we can work with Day 1, and then
replicate the procedure for the rest of the pages. By adding our styles for day1, day2 and
day3 to app.tss, well be able to
define them only once, and not replicate them in their individual stylesheets. Go ahead and
create an empty file named app.tss inside app/styles. Make sure you check the companion
code for this section to see the full stylesheet. Below Ill explain the most important
aspects of it.
. table [ platform = ios ]:{
separatorStyle : Titanium . UI . iPhone . TableViewSeparatorStyle . NONE
}
. row [ platform = ios ]:{
height :155 ,
selectionStyle : Titanium . UI . iPhone . TableViewCellSelectionStyle .
NONE
}
. row [ platform = android ]:{ height :155

}
. timecol :{
width :40% ,
left :0 ,
top :5 ,
bottom :5 ,
layout : vertical
}
. descriptioncol :{
width :60% ,
right :5 ,
backgroundColor :# efefef , top :5 ,
bottom :5 ,
layout : vertical
}

The separatorStyle property of the TableView allows you to specify whether you want a
line separating the rows or not. Were setting this property to show no separator. Were
then disabling the row selection on iOS, and this for aesthetics only. Finally were setting
the left property of the Time Column to 0 and the right property of the Description
Column to 5 to make sure the content aligns correctly on the screen.
Figure 5.13 shows how the app looks so far.

Figure 5.13:
TableView on iOS and Android
In this section we saw how to create a cross-platform TableView and how to use Alloy
global styles to share styling across similar views. The following section covers data
access. Well be looking at three different techniques, so consider this point a checkpoint
well be coming back to.

5.3 Using local data storage


In this section will dynamically fill the rows of our TableView. Well be implementing this
feature using three different techniques: Using local JSON files and persistent properties,
using a local SQLite database and using Alloy built-in Backbone.js Models.

5.3.1 Persistent App Properties


Titanium provides a cross-platform, persistent mechanism for storing data as properties,
that will be available throughout your whole app. Any data stored in these properties will
still be available after re-launching the app, and even after rebooting the device.
These properties can be found at Titanium.App.Properties and offers methods for storing
different data-types:
Boolean data: setBool and getBool
Double numbers: setDouble and getDouble
Integer numbers: setInt and getInt
Arrays : setList and getList
Objects: setObject and getObject
String: setString and getString
To make this properties work as a database, we will bundle JSON files with the app,
loading them into Titanium properties and from them populate our TableView.
If you wish to remove a property youve already created you can use the
Ti.App.Properties.removeProperty method. For full reference of Persistent Properties refer
to http://docs.appcelerator.com/titanium/3.0/#!/api/ Titanium.App.Properties
The JSON data files
If youre not familiar with JSON files, make sure you checkout the JavaScript Refresher
Appendix. For our app, the database will contain 5 fields:
time : Will include data in the format 8am-9am
room : The name of the room or area in the venue where this item takes place
title : Title of the talk or entry
speaker : Name of the speaker
description : Description of this talk
speakerbio : Short speaker bio
JSON files could be edited with any text editor, but to make it easier to create and/or
modify JSON files, Id suggest you use a JSON editor. There are many online and offline
options. I use and recommend jsoneditoronline.org. Figure 5.14 shows the
jsoneditoronline.org interface while editing the JSON file for this app.

Figure 5.14: JSON Editor On-Line


JSON Editor Online will allow you to paste a plain-text JSON file, and automatically be
able to, not only visualize in as a hierarchical interface, but you can also easily add new
data, modify and reorder as needed.
Go ahead and create three data files following this format, one for each day, and name
them day1.json, day2.json and day3.json. Then create a folder named data inside your
/app/assets folder and drop the files there as seen in Figure 5.15. Alternatively, you can
grab the ones Im including with the companion code for this chapter.
Im using the .json extension for readability, but these files are simple text files and could
have any name or extension.

Figure 5.15:
Location of data files
Now that we have the data files ready, we can go ahead and build the routines that will
load the data onto the tables. At this point we want to step back and remember that all
three pages, Day 1, Day 2 and Day 3 are exactly the same, and the only thing that changes
is the data they show. You may feel tempted to write the code for Day 1 and then copy and
paste it to Day 2 and Day 3, and although this works, its not the best approach; the right
approach is building a CommonJS module you can reuse for all three pages. This will
ensure that your code is modular, and since all three pages work in the same way, making
a change in the module will automatically take effect if all three.

Loading the data


All alloy CommonJS modules are stored in a folder needs to be called lib and must live
in /app, at the same level as your controllers, views and styles. This folder is not created
by default so go ahead and create it. Inside this folder create an empty file and name it
schedulemod.js, which will hold a CommonJS module for the Schedule tab.
If youre not a programmer, its important to know that when you write CommonJS
modules, or Alloy controllers for that matter, youre using pure JavaScript and Titanium
Classic. At this moment you should decide if you want to brush up on your JavaScript
skills, or find someone else on your team to work on these functionalities.
The first thing we need to do is create a function that will load the data from our data file
into the Global Property.
function loadSchedule ( day ) {
if (! Ti . App . Properties . getBool ( day +- loaded , false )){ var filename = / data / + day + . json ;
var f = Ti . Filesystem . getFile ( Ti . Filesystem . resourcesDirectory , filename );
var contents = f. read () ;
Ti . App . Properties . setObject ( day , JSON . parse ( contents ));
Ti . App . Properties . setBool ( day +- loaded , true ) ; }
}
exports . loadSchedule = loadSchedule ;

The function above takes care of loading the data from the data files. Also youll notice
that its receiving a variable named day. This is because everything we write in this
module must be generic, and by sending the day to work with, we make sure this function
will work for all three days.
To call this function, simply open day1.js, create the day variable and call the module,
as seen below.
var dayTag = day1 ;
require ( schedulemod ) . loadSchedule ( dayTag );

At this point your data is properly loaded into memory. Now lets see how to create our
row template and load them into the TableView. Create a new controller named dayrow,
either using the Studio menus or the CLI. This will create dayrow.js, dayrow.xml and
dayrow.tss. This last file we wont use because our styles are global in app.tss, but you can
leave the file empty if you wish. Open day.xml where we created our TableView Row, and
move the whole row to dayrow.xml, as illustrated in Figure 5.16.

Figure 5.16: Move


TableViewRow to dayrow.xml
To load the data onto the Table well create the loadTable function in schedulemod.js.
function loadTable ( tableObject , dayTag ){
var tableData =[];
Ti . App . Properties . getObject ( dayTag ). forEach ( function ( item ,
index ){
item . index = index ;

var row = Alloy . createController ( dayrow , item ).


getView () ;
tableData . push ( row ) ;
})
tableObject . setData ( tableData );
}
exports . loadTable = loadTable ;

You may have noticed in this function were using the second argument of
Alloy.createController. When you call Alloy.createController(dayrow), Alloy loads the
dayrow.xml file as an Object and when you call getView() its converted into a Titanium
View. Now, by adding the second argument, youre actually sending data to dayrow.
Figure 5.17 illustrates how data is being inserted into your code.

Figure 5.17:
Creating controllers dynamically
Youre looping through all of the items in Ti.App.Properties.getObject(daytag). For each
item in this Array youre first adding the actual index so we can keep track of the order in
which they came. Then we call createController and we send the whole object. Alloy will
look for dayrow.xml, but before giving it to you, itll call dayrow.js and will pass along
the object in the item variable. The code in dayrow.js, and all controllers for that matter
start with this line:
var args = arguments [0] || {};

After this line is executed, Alloy assigns the contents of the item variable to the args
variable, so from your controller code youve just gained access to the data passed by
createController. This all happens before your dayrow.xml is rendered, giving you the
opportunity to add values to your view. In Figure 5.18 you can see how data is being
passed from dayrow.js to dayrow.xml.

Figure 5.18:
Populating data in views

So in summary, for every iteration of the loop, the current item in the JSON object is being
sent to dayrow.xml, this data is being used to populate the XML file, rendered and
returned to the variable row. Each row is being collected in the Array named tableData.
Once weve gone through all the rows, we have an Array of TableViewRows that we then
set on the TableView by calling setData.
Next lets make sure we call the loadTable function by going to day1.js and make adding a
call like so:
require ( schedulemod ) . loadTable ($. day1table , dayTag );

Notice that since this is a generic function, we need to send the table to which the data will
be added and the dayTag variable used to grab the data from the persistent property.
Day 1 is ready. Now to enable the list for Day 2 and Day 3, simply copy the contents of
day1.xml over to day2.xml and day3.xml, making sure you change the id of the table.
< Alloy >
< TableView id = day1table class = table > </ TableView >
</ Alloy >

Then copy the contents of day1.js over to day2.js and day3.js changing the dayTag
variable and the reference to the table to be used.
var args = arguments [0] || {};
var dayTag = day1 ;
require ( schedulemod ) . loadSchedule ( dayTag );
require ( schedulemod ) . loadTable ($. day1table , dayTag );

This completes the loading of schedule data using JSON files and persistent properties.
Now lets explore how to achieve the same results but using local SQLite databases.

5.4 SQLite
Both iOS and Android have native support for SQLite databases. SQLite is a server-less
database library that allows you to have a database that you access locally. The main
advantage is that the data will come pre-loaded with the app, instead of having to load it at
runtime as well as store or modify data at runtime. Going forward, SQLite will give you
the flexibility of having multiple tables and query them using SQL Syntax, although thatll
not be needed for our app.
To create databases you need to use third-party software. In my opinion, the easiest is the
free SQLite Manager Firefox Extension you can find at https://addons.mozilla.org/enUS/firefox/addon/sqlite-manager/. Download and Install this extension on your Firefox
browser, and then go to Firefox >Tools >SQLite manager to launch it. Select Database
>New Database and enter scheduledata for its name and then select your app/assets
folder as its home (Figure 5.19). This will create the file scheduledata.sqlite in /app/assets.

Figure 5.19: Create SQLite Database Youve successfully created an empty database. Now
we need to import our JSON files onto it. SQLite Manager has an import function, but
only accepts SQL and CSV files. The easiest way to go around this is to convert our JSON
files to CSV, and for this we can use a free online tool called ConvertCSV found at
http://www.convertcsv.com/json-to-csv.htm, shown in Figure 5.20.

Figure 5.20:
Convert JSON to CSV
On this page, select your day1.json and click on Convert JSON to CSV. This will load
your JSON file and display a comma-separated values version below. The Include header
in first row checkbox will make the next step easier. Then select Save to Disk to save the
CSV file in your local computer.
Now go back to your SQLite Manager and select Import Wizard. From this screen select
the file from the previous step, enter day1 as the database name and if the first row
contains the column names, make sure you specify it in this screen as seen in Figure 5.21

Figure 5.21: Import CSV to SQLite


Select Ok and the next screen will show you the fields that where found (Figure 5.22).
Make sure everythings correct and hit Ok.

Figure 5.22:
Confirm Table Schema
Figure 5.23 shows the results after importing the CSV file. You can make changes to the
data at this point, or add new records if needed.

Figure 5.23: SQLite


Data Browser
Now, repeat the same process for day2 and day3 until you have all the data in your
scheduledata.sqlite database.
Having the data ready, its now time to modify our code to use SQLite databases instead of
Global Properties as before. Titanium has a very robust implementation of SQL found at
http://docs.appcelerator.com/titanium/ latest/#!/api/Titanium.Database. Working with
SQLite however is not very natural to JavaScript developers. For this reason Ill be using a
library named JSSQL which you can find at https://github.com/ricardoalcocer/
jssql/blob/master/app/lib/com.alcoapps.dbhelper.js . I designed this library to make
Titanium SQL Databases feel like working with JavaScript objects. Using this library will
make your code more readable and easier to implement the changes in our existing code.
This library opens a database and returns it as a JSON object, so as youll see there are
only a few changes to make. You can however still read the librarys code and learn more
about how its implemented.
Lets go back to our checkpoint, just before we started implementing the Persistent
Properties. Download the library and save it in /app/lib with the name
com.alcoapps.dbhelper.js. Your app only requires two changes. First, open day1.js, day2.js
and day3.js and remove the line that calls loadSchedule; we no longer need it since the
data comes pre-loaded.
var args = arguments [0] || {};
var dayTag = day1 ;
require ( schedulemod ) . loadSchedule ( dayTag ); require ( schedulemod ) . loadTable ($. day1table , dayTag );

Then open up schedulemod.js and delete the loadData function and its export. Then, we
need to modify loadTable so its now using the JSSQL library instead of global properties.
function loadTable ( tableObject , dayTag ){
var DBH = require ( com . alcoapps . dbhelper ) ;
var db = new DBH . dbhelper ( / scheduledata . sqlite , scheduledata ) ; var scheduleData = db . get ({
fields : *,
table : dayTag
}) ;
var tableData =[];
scheduleData . forEach ( function ( item , index ){
item . index = index ; // add the index to the object
var row = Alloy . createController ( dayrow , item ). getView () ;
tableData . push ( row ) ;
})
tableObject . setData ( tableData );

By calling db.get, were actually querying the SQLite database for all the records in the
table named as the dayTag variable, and the results are a JSON Object. This means that
from here on out, the code remains the same as before.
iOS local database location
Its important to keep in mind that when you ship a database with your app, the phone will
actually move it to a different location, this because on iOS the apps directory is readonly. This however creates a small problem. Once your apps database is used for the first
time, its there for the lifetime of your app, so if you ship a different version of the
database with a new build, the database will still be untouched because it already exists.
You can know the location of the database by calling the file property on the database
object (http://docs.appcelerator.com/titanium/3.0/#! /api/Titanium.Database.DB-propertyfile).
If you need to make changes to an existing database as part of a new version of your app,
youll need to use the Database functions to perform the required changes. The JSSQL
library contains methods for creating new tables, editing, deleting, etc., or you could also
use regular SQL Strings against the database.
Its also important to remember that SQLite databases are not encrypted; theyre not text
files, but dont offer any built-in security. If you plan on storing sensitive data, Id suggest
you encrypt it before saving. There are many JavaScript-based encryption libraries, or you
could use the Securely Titanium module found at
https://github.com/benbahrenburg/Securely, which besides string encryption offers a
whole security layer for your Titanium apps.

5.5 Alloy Models


Our third and last method for storing data is using Alloy Models. Alloy comes with builtin support for BackBone.js models. Backbone.js is a well-known and widely adopted
JavaScript library used to provide easy-to-use data storage for web applications.
Appcelerator apps are not web apps, but after all the coding is written in JavaScript, so
Backbone is seamlessly integrated. For more information about Backbone, you could
check the book Beginning Backbone.js at http://www.apress.com/9781430263340.
To create data models, right click on your project explorer and select Alloy Model as seen
in Figure 5.24.

Figure 5.24: Create model


Then, on the next screen (Figure 5.25), set the name of the model (like the name of a
database table) and set the fields for your data model. Notice that Im adding a field
named myindex, which well use as a unique identifier for retrieving data later on.

Figure 5.25: Create model schema


When you click Ok, Alloy will have created the model file inside your app/models folder.
Do this for day1, day2 and day3. Below you can see what the model file for day1 looks
like.
exports . definition = {
config : {
columns : {
time : TEXT , room : TEXT , title : TEXT , speaker : TEXT ,
description : TEXT ,
speakerbio : TEXT ,

myindex : INTEGER
},
adapter : {
type : sql ,
collection_name : day1
}
},
extendModel : function ( Model ) {
_. extend ( Model . prototype , {
// extended functions and properties go here
}) ;
return Model ;
},
extendCollection : function ( Collection ) {
_. extend ( Collection . prototype , {
// extended functions and properties go here
}) ;
return Collection ; }
};

You can look at Alloy models as a combination for our two previous methods: loading
data from JSON files and storing data in SQLite databases. The fact is that Alloy Models
provide an abstraction so you can load and manipulate data in SQLite databases without
having to learn the Titanium.Database syntax. If youre a web developer and already know
BackBone, then youll feel right at home and will be able to leverage its features and
functionality in your Titanium apps.
From the JavaScript code standpoint, its not that much different either. Since our code is
modular and organized, the only changes we need to make in our code are on
schedulemod.js. First lets take a look at our modified loadSchedule function.
function loadSchedule ( day ) {
if (! Ti . App . Properties . getBool ( day +- loaded , false )){ var filename = / data / + day + . json ;
var f = Ti . Filesystem . getFile ( Ti . Filesystem . resourcesDirectory
, filename ) ;
var contents = JSON . parse (f. read () );
contents . forEach ( function ( thisDay , index ) {
var model = Alloy . createModel ( day , {
time
room
title
speaker
description
speakerbio
myindex
}) ;
model . save () ;
}) ;
contents = null ;
f = null ;
: thisDay . time ,
: thisDay . room ,
: thisDay . title ,
: thisDay . speaker ,
: thisDay . description ,
: thisDay . speakerbio ,
: index
Ti . App . Properties . setBool ( day +- loaded , true ) ; }
}

Just like before, we need to load the JSON file using the FileSystem function. Once we
have it, we use JSON.parse to convert it to an object. We didnt do this before because this
conversion was performed by the Ti.App.Properties.setObject method. Once we have our
data in JSON format, we loop through them, and use the Alloy.createModel method to
create a variable with the structure of this data model, and assign the values to its

properties. We then save the model and continue with the next record. After this function
finishes, we have effectively loaded all the records into an SQLite database, all handled
invisibly to you by Alloy and Backbone. Now lets take a look at our modified loadTable
function.
function loadTable ( tableObject , dayTag ){
var tableData =[];
var day = Alloy . Collections . instance ( dayTag );
day . fetch () ;
var dayJSON = day . toJSON () ;
dayJSON . forEach ( function ( item , index ){
item . index = index ;
var row = Alloy . createController ( dayrow , item ). getView () ; tableData . push ( row ) ;
})
tableObject . setData ( tableData );
}

Theres much more to Alloy Models, but after all, its not so much an Alloy feature, but
the features of BackBone.js. If youd like to learn more visit BackBones website at
http://backbonejs.org/. If youd like to learn about other ways of using Backbone with
Alloy you can go to Alloys official Github repository at
https://github.com/appcelerator/alloy/tree/master/test/apps
Knowing that our data exists, we can load an instance of a collection for the day were
working with. We then call the fetch() method to load all the data into the collection and
use the toJSON() method to convert it back to JSON. After doing this, all the rest is the
same as before.

5.5.1 Responding to TableView clicks


We now have our data in a data source, and a vertical list showing all the items. Each row
is showing an item from the schedule. We now want to implement the capability of
clicking on a row and get more details about the session, as shown in Figure 5.26. This
Figure also shows how well be using the data we have in our data source in our new
window. In the process of implementing this youll learn two important things: how to
open new windows and pass data to them, and how to use the iOS Navigation Window
that comes pre-baked into the TabGroup.

Figure 5.26:
TalkDetails Screen
To enable click events in our TableView, we simply add an onClick event listener to our
TableView tag.
< TableView id = day1table class = table onClick = tableclick / >

Im using Day 1 for this example, but once were done, well need to replicate the
procedure for Day 2 and Day 3. The tableclick function used as the callback for the
onClick event needs to be defined inside day1.js.
function tableclick ( evt ){
}

From this click event well be grabbing data from the clicked row, and sending it over to
our new window. However, the row doesnt contain all the data we need; were missing
the speakerbio, so before we do anything, we need to call our database and get the full
details of the row that was clicked.

5.5.2 Getting data from a clicked row


We want to keep our code modular and generic, so well write this function inside
schedulemod.js. This new function will be called getTalkDetails, and will receive the
dayTag and the id of the row that was clicked; more about this shortly. This code is
specific to the type of data source, so Ill explain how to perform the operation in the case
of Persistent Properties, SQLite Databases and Alloy Models.
Persistent properties version
When we use Persistent Properties, the data is stored in an Array. Also as you recall we
stored the index (ordinal) of each record as part of each TableView row. This means that
row 5 in our TableView represents the record 5 in our data source. Because of this 1:1
relationship, getTalkDetails while using persistent properties is as follows:
function getTalkDetails ( day , row ){
return Ti . App . Properties . getObject ( day )[ row ];
}
exports . getTalkDetails = getTalkDetails ;

In our next two versions well be using SQL Statements. If you dont know how to create
SQL Strings, please refer to http://www.sqlite.org/lang.html for a reference on the SQL
Syntax compatible with SQLite.
SQLite Database version
In the case of our SQLite Database, we didnt explicitly store the index. However, SQLite
automatically sets a hidden property named rowid, which we can use in the same manner
as our previous scenario.
function getTalkDetails ( day , row ){
var DBH = require ( com . alcoapps . dbhelper ) ;
var db = new DBH . dbhelper ( / scheduledata . sqlite ,
scheduledata ) ;
var rec = db . exec ( SELECT * from + day + where rowid = + parseInt ( row +1) );
return rec [0];
}
exports . getTalkDetails = getTalkDetails ;

In our SQLite scenario, the internal rowid starts at 1 instead of 0, so we need to add one to
the row id we receive from our TableView. Also, notice Im converting the value to
Integer, otherwise JavaScript will treat the addition operation as a string concatenation.
Alloy Models version
With Alloy Models the procedure is similar to the SQLite version. As you remember, we
added the myindex field to our data model, using it for the same purpose as with the
version using Persistent Properties. In this version of the function well be using an SQL
String, querying for the myindex field, and sending the SQL String straight to the
Backbone collection.
function getTalkDetails ( day , row ){
var schedule = Alloy . Collections . instance ( day );
schedule . fetch ({ query : SELECT * FROM + day + WHERE myindex =
+ row }) ;
return schedule . toJSON () [0];
}
exports . getTalkDetails = getTalkDetails ;

Now lets go back to our tableclick event callback, from where well be calling the
getTalkDetails function. The function requires the day and row arguments. The day is easy
because its the dayTag variable we already have. The clicked row however we need to
grab it from the actual TableView. The evt variable contains the object described in Figure
5.27.

Figure 5.27: Event object


If at any point youd like to inspect the data thats returned by any event, simply write its
contents to the console using the syntax console.log(JSON.stringify(evt))
This object contains information about the event, as well as information about the row that
generated it. The row property is equivalent to the TableViewRow tag, and in that tag is
where we added our rowId, which we can access via evt.row.rowId.
Finally our event needs to open the new window and pass the data to it, and for this well
use a pattern very similar to what we did with our row template. However, the code is
exactly the same for all three days, so to avoid repeating the code, well handle this in
schedulemod.js. Our final tableclick function looks as follows.
function tableclick ( evt ){
var talkDetails = require ( schedulemod ) . getTalkDetails ( dayTag , evt . row . rowId );
require ( schedulemod ) . tableClick ( evt , talkDetails , dayTag ); }

You can see our generic method inside schedulemod in listing 5.6. Listing 5.5: Generic
tableClick function
function tableClick ( evt , talkDetails , dayTag ){ var w= Alloy . createController ( talkdetails ,{ rowId : evt . row . rowId ,
talkDetails : talkDetails ,
day : dayTag
}) . getView () ;
w. addEventListener ( open , function ( evt ){
if ( OS_ANDROID ){
var activity = evt . source . getActivity () ;
var actionbar = activity . actionBar ;
actionbar . title = talkDetails . title ;
if ( talkDetails . speaker !== ) {
actionbar . subtitle = String . format ( L( presented_by ) , talkDetails . speaker );
}
actionbar . displayHomeAsUp = true ;
actionbar . onHomeIconItemSelected = function () {

evt . source . close () ;


}
}
})
Alloy . Globals . tabGroup . activeTab . open (w ,{ animated : true }) ;
}
exports . tableClick = tableClick ;

The function above will work for all three days. By keeping it inside shedulemod.js you
make sure your code is kept modular and organized and if you need to make any changes,
you make them in a single place.
Notice that we opened the window using the line
Alloy . Globals . tabGroup . activeTab . open (w ,{ animated : true }) ;

This global variable doesnt exist at the moment, but we need it because we cant access
the TabGroup from here. Were running from an external CommonJS module that runs
independent from the apps context. To make it available we add the following line to
index.js.
Alloy . Globals . tabGroup = $. index ;

Whats so important about this? Well this opens the new window inside the current Tab.
On Android this has no real effect because on Android tabs are shallow: theres no
navigation inside them. On iOS however, you can have navigation inside each Tab, so by
opening your window using this line, youre effectively creating a Navigation Controller
inside your tab, as seen in Figure 5.28.

Figure 5.28: iOS Navigation Controller


This has three main benefits:
The Window will open with a native slide-in animation
iOS will provide you with an automatic back button with the name of the previous
window, in this case Schedule 7 iOS will automatically expose the function executed
when you tap on the back button, as well as the capability of closing the window by
swiping from the left edge of the device.
We have our event listener ready, so now its time to create the talkdetails screen. Go
ahead and create a new controller named talkdetails. Listing 5.6 shows the XML for this
new controller.
Listing 5.6: talkdetails.xml
< Alloy >
< Window id = talkdetails class = container > < View class = banner / >
< ScrollView class = scrollview >
< View class = titlebox > < Label id = talktitle / > < Label id = time / > < Label id = room / >
</ View >
< Label id = description / > < Label id = speaker / > < Label id = speakerbio / >
</ ScrollView >
</ Window >
</ Alloy >

In the code above were adding all of our screen components to a ScrollView. Since we

dont have control over the size of the data on this screen, there may be cases where the
speaker bio will not fit on the screen. By adding all of our UI components to a ScrollView,
we make sure that everything fits perfectly and those components that fall outside of the
visible area are still available by scrolling up and down. Next, we need to apply the styling
for this screen. Theres nothing new in this stylesheet, so make sure you check the
companion code for a full listing.
Finally, our talkdetails.js (listing 5.7) receives the data from our tableClick function and
assembles it in the XML, just like we did before with our row template.
Listing 5.7: talkdetails.js
var args = arguments [0] || {}; var talkDetails = args . talkDetails ;
$. talktitle . text $. time . text = $. room . text = $. description . text = talkDetails . title ;
talkDetails . time ;
talkDetails . room ;
= talkDetails . description ;
if ( talkDetails . speaker !== && talkDetails . speaker !== null ){ $. speaker . text = String . format (L( about ) , talkDetails . speaker );
} else {
$. speaker . text = ;
}
if ( talkDetails . speakerbio !== && talkDetails . speakerbio !== null ){
$. speakerbio . text = talkDetails . speakerbio ;
} else {
$. speakerbio . text = ;
}
function closewindow ( evt ){ $. talkdetails . close () ;
}

One last thing before we finish, if you run the app at this point, youll notice a minor
problem (Figure 5.29).

Figure 5.29: Events


conflict
Our TableView has vertical scrolling capabilities. However, the TableView is contained
within a ScrollableView, which also has scrolling capabilities. We are using the
ScrollableView scroll event to synchronize the page with the button on the TabbedBar,
which as I mentioned before was an optional feature. With Titanium you have to be
careful with what is called Event Bubbling. This means that events from an object are
passed (bubbled) back to its parent. In this case, the scrolling event of the TableView is
being passed over to the ScrollableView, triggering our scroll listener, but with not enough
data to synchronize with the TabbedBar. To solve this, we simply cancel the Event
Bubbling on the TableView, making the events stop as soon as they happen. Open day1.js,

day2.js and day3.js and add the following function.


function tablescroll ( evt ){
evt . cancelBubble = true ;
}

Then open day1.xml, day2.xml and day3.xml and add this event listener to the TableView
tag.
< TableView id = day1table class = table onClick = tableclick onScroll = tablescroll >

This completes our implementation of the Schedule Tab. You can run your app at this
point and see how it effectively shows the schedule data in both iOS and Android using
the platform-specific UI elements we selected. 5.6. Summary

5.6 Summary
In this chapter weve dealt with several important topics that will apply to all your apps.
Third-party native modules
There will be times when a certain feature or screen control is not available in the
Titanium API. For these cases you should explore the large array of third-party native
modules that are available. Most of these can be found in the official marketplace at
http://marketplace.appcelerator.com.
Working with Table Views
We learned how to implement Table Views to display data in a list that scrolls vertically,
just like the one in the Twitter and Facebook mobile apps. In the process of implementing
it, we saw how to use Alloy to load dynamic data onto the table and how to respond to
table clicks to open secondary windows.
Implementing databases via App Properties, SQLite databases and Alloy Models
The data strategy to use is always to be decided in a case-by-case basis. There will be
times when Properties are enough, while there may be other times when you want to use
Backbone models. Make sure you analyze your future projects so you can decide on the
best strategy for you.
Through this chapter we explored three methods of data access, which resulted in three
different projects, each with its own set of programming routines to access the data
sources. The three projects are included with this chapter and I suggest you run them and
use them to follow along with your reading.
In chapter 6 well implement the remaining functionalities of our app, using web services,
Twitter integration and well learn how to open web pages and open the phones dialer.

Chapter 6

ListView, Web Services and Twitter


Integration
This chapter covers:
Opening Web Pages and the Phone Dialer
Using the ListView
Pulling data from Twitter
Connecting to Web Services, in particular to YouTube
Changing ActionBar icons on tab change
In Chapter 5 we saw how the TableView allowed us to build vertical scrollable lists.
Although TableViews were useful in that use-case where the content was only text, there
are cases where lists get more complex. In this chapter well be creating lists that display
remote data from Twitter and YouTube. Not only is this data in image format (as opposed
to text), but also the data is being fetched remotely. The TableView can be used for this,
but at some point youll run into problems that will make your lists sluggish and your app
could even become unresponsive. In this chapter well use another component called
ListView, which was designed specifically with optimal performance in mind.
One of the lists well be building will be filled out with Twitter data. Twitter has a very
strict security and privacy policy, which requires any developer to register as a developer,
and obtain API Keys, which will be used every time you request data. This chapter will
show you how to register your app in the Twitter developer portal, and how to implement
the necessary libraries to effectively fetch data from Twitter.
Another important topic covered in this chapter is consumption of Web Services. In
general terms, web services are consumed by performing HTTP connections. In this
chapter youll learn how to establish an HTTP Connection to any web server, receive the
JSON response, parse it and use it to fill out the ListView.
In the process of working with Twitter and YouTube, well also get into the topics of
opening the web browser, establishing phone calls and opening other apps from your app.
This is a very exciting chapter, full of code that could be used in virtually any app
scenario. Lets do this!

6.1 Opening a Web Browser and initiating phone calls


The second tab in our app is the Venue tab, where we show information about where the
event will take place. This window is pretty much straightforward, as you can see in
Figure 6.1.

Figure 6.1: Venue


Window
6.1. Opening a Web Browser and initiating phone calls
We will place all the components inside a ScrollableView, like with did in Chapter 5 for
the talk details. To this we add the venue title. We then add the venue image, the venue
address, venue phone number and venue description.
< Alloy >
< Window class = container >
< ScrollView class = scrollview >
< View class = titlecontainer >
< Label class = venuetitle / >
</ View >
< View class = venueimage / >
< View class = addressrow >
< ImageView class = mapicon / >
< Label id = maptext class = maptext onClick = clickmap />
</ View >
< View class = phonerow >
< ImageView class = phoneicon / >
< Label id = phonetext class = phonetext onClick = clickcall />
</ View >
< Label class = venuedescription > </ Label >
</ ScrollView >
</ Window >
</ Alloy >

To make it easy to maintain, the title and description will be stored in the language files
(you already know how to set these.) The venueAddress and venuePhoneNumber will be
stored as Alloy Global Configuration in config.json.
global : {
venueAddress : 747 Howard St , San Francisco , CA 94103 ,
venuePhoneNumber : + (415) 974 -4000
}

We then create our controller, as shown in listing 6.1. Listing 6.1: venue.js

var args = arguments [0] || {};


$. maptext . text = Alloy . CFG . venueAddress ;
$. phonetext . text = Alloy . CFG . venuePhoneNumber ;
function clickmap ( evt ){
Ti . Platform . openURL ( https :// maps . google . com / maps ?q = + encodeURIComponent ( Alloy . CFG . venueAddress )) ;
function clickcall ( evt ){ if ( OS_IOS ){
if ( Ti . Platform . canOpenURL ( tel :// + venuePhoneNumber )){
Ti . Platform . openURL ( tel :// + venuePhoneNumber ); } else {
Alloy . CFG .
Alloy . CFG .
alert (L( no_phone ) ); }
} else {
Ti . Platform . openURL ( tel :// + Alloy . CFG . venuePhoneNumber );
}
}

In the listing above Im using the iOS-only function canOpenURL. The reason is
because iOS apps can be used on an iPod Touch or iPads, and these devices have no phone
functionality. By using this function we make sure that we only try to initiate a phone call
if it is at all possible.
This takes care of the Venue Tab. Make sure you checkout the stylesheet in the companion
code. Now lets move on to the Conversation tab, where well learn to use the ListView
component.

6.2 The ListView


The ListView is a component very similar to the TableView we saw in the previous
chapter. The TableView is a great component to display vertical lists. However, its not
really very efficient in displaying complex tables, such as those with heavy graphic
content. The reason is purely technical.
If you remember from the schedule tab, with the TableView you create TableViewRow
objects, which you then add to an array, and then send the whole array of objects to the
TableView, as seen in the following snippet from Chapter 5.
function loadTable ( tableObject , dayTag ){
var tableData =[];
Ti . App . Properties . getObject ( dayTag ). forEach ( function ( item , index
){
item . index = index ; // add the index to the object
var row = Alloy . createController ( dayrow , item ). getView () ; tableData . push ( row ) ;
})
tableObject . setData ( tableData );

This list style worked perfectly fine for our schedule because its only displaying text data.
The problem with this implementation is that Titanium, as a bridge between native code
and JavaScript, needs to keep an active link between the native component and the
JavaScript one, and the more complex the rows get, the heavier the memory load for your
app. To fix this, Appcelerator developed the ListView component, which you essentially
use for the same purpose, but differs in its technical implementation and its usage. Figure
6.2 shows our desired output.

Figure 6.2:
Conversation Window showing latest tweets
As you can see, the end result is just like the TableView, a vertical list. Lets now look at
how to write the markup for this list.

6.2.1 Writing the ListView markup


To implement this list, the ListView uses the concept of row templates, which you define
beforehand and illustrated in Figure 6.3.

Figure 6.3: How


ListView templates relate to the screen layout
Each template is basically the Titanium code required for the row, but instead of actual
data, you use special data-binding properties, which will be automatically filled out by the
ListView engine. You then assemble a data structure with the data for all rows, and to each
item you specify the template to use. Titanium will then go down to the native level and
will build the list in the most memory and CPU efficient way.

As you can see in Figure 6.3, you first declare the ListView. Just like with the TableView
the event listener is applied at this level and not at the row level. Then you have a
Template to which you add the templates you wish to use for the different rows of this list,
and this has a very important implication.
Inside a ListView you can have rows that follow different content structures. For example
you can have one row that has an image on the left, the following row with an image on
the right and the remaining rows with no images. For each of these rows youd create
different templates. In this example were creating the loading template, which defines a
row that will be shown to indicate that the list is refreshing. Next we define a template
with name rowtemplate, which declares the actual structure of each data row. Finally,
before we close the ListView tag, we need to add the ListSections, which is basically the
container that will hold the actual list data. Listing 6.2 shows how conversation.xml looks.
Listing 6.2: conversation.xml
< Alloy >
< Window id = conversation class = container >
< RightNavButton platform = ios >
< Button systemButton = Ti . UI . iPhone . SystemButton . REFRESH
onClick = dorefresh / >
</ RightNavButton >
< ListView id = tweetlist onItemclick = doclick >
< Templates >
< ItemTemplate name = rowtemplate
< ImageView bindId = avatar
class = rowtemplate > class = avatar / >
< Label bindId = name class = name / > < Label bindId = screen_name class = screen_name
/ >
< Label bindId = tweet class = tweet / > </ ItemTemplate >
< ItemTemplate name = loadingtemplate class =
loadingtemplate >
< Label bindId = loading class = loading / >
</ ItemTemplate >
</ Templates >
< ListSection name = notification / >
< ListSection name = tweets / >
</ ListView >
</ Window >
</ Alloy >

Notice in the listing above that were adding an iOS-only refresh button. On iOS buttons
go in the Title bar, which in this case is added to each Tab using the special
<LeftNavButton >and <RightNavButton >tags. On Android however, the refresh button
goes in the ActionBar, which we cant access from here. Well deal with it later from
index.js
The Stylesheet for this window has nothing special so Ill leave it to you to check it out in
the source code for the chapter. So far we have the screen structure to display the data. The
data for this screen will come from Twitter, so lets learn how to connect to Twitter.

6.2.2 Connecting to Twitter


Connecting to Twitter is not trivial. Twitter has some special security layers that where
recently implemented to make sure that data is secure and that the service is not overused.
We will not get into the specifics of how the Twitter connection works; thats beyond the

scope of this book. Well however use a Twitter JavaScript library named codebird.js,
which was modified for Titanium by one member of the Titanium user community and
can be found at https://gist.github.com/viezel/5781083.
Download the library and place it in your app/lib folder. With this we take care of all the
complexity of connecting to Twitter. Its important to know that this library gives you
access to perform a host of different operations against twitter, such as complex searches
and posting tweets. However for our app well only be reading the feed based on a given
hashtag.
To use the library, we need to formally register a new Twitter consumer app. To register,
head over to https://apps.twitter.com/ to obtain your Twitter API Keys. Select Create
New App from the main screen, as seen in Figure 6.4.

Figure 6.4: Create a


new Twitter App
On the next screen (Figure 6.5) add the meta-data for you app. This information is not
really relevant to your Titanium app, but Twitter still needs to know some basic
information about each app thatll be using its data.

Figure 6.5: Add


your apps meta-data
Finally, from the next screen (Figure 6.6), click on the Keys and Access Tokens tab, and

copy the API Key and API Secret.

Figure 6.6: Grab


API Key and API Secret
We want to be able to change these keys with ease, so lets add them as global properties
to config.json like we did before, and well also add the hashtag well search for while
were at it.
global : {
venueAddress : 747 Howard St , San Francisco , CA
94103 ,
venuePhoneNumber : + (415) 974 -4000 ,
twitterHashTag : # tidev ,
twitterConsumerKey : the_given_key ,
twitterConsumerSecret : the_given_secret
}

Now that we have our keys and our Codebird.js library, well write the code to speak to
the library. Well create another module in /lib which well call socialfeeds.js. This will be
the module that will actually talk to the Codebird library, and since well also need to
implement YouTube feeds, well use it to store all our social code. Listing 6.3 shows the
code for socialfeeds.js. Notice that this is not really Titanium or Appcelerator code, so Ive
abstracted it as much as possible. The usage is the same as seen in the code repo at https:
//gist.github.com/viezel/5781083, but using our keys and structured in a much more
modular way.
Listing 6.3: socialfeeds.js
var Codebird = require ( codebird ) ; var cb = new Codebird () ;
var getFeed = function ( args ){
switch ( args . type ){
case TWITTER :
cb . setConsumerKey ( args . consumerKey , args . consumerSecret ) ; var bearerToken = Ti . App . Properties . getString ( TwitterBearerToken , null
);
if ( bearerToken == null ){
cb . __call (
oauth2_token ,
{} ,
function ( reply ) {
var bearer_token = reply . access_token ; cb . setBearerToken ( bearer_token );
Ti . App . Properties . setString ( TwitterBearerToken ,
bearer_token );
fetchTwitter ( args . action , args . searchstring , args .
max , args . success );
}
);
} else {
cb . setBearerToken ( bearerToken );

fetchTwitter ( args . action , args . searchstring , args . max , args . success );


}
break ;
} }
function fetchTwitter ( action , searchstring , max , success ){ var params = {
q : Ti . Network . encodeURIComponent ( searchstring ) , count : max
};
cb . __call (
action ,
params ,
function ( reply ) {
success ( JSON . stringify ( reply . statuses )); },
true // this parameter required
)
}
exports . getFeed = getFeed ;

This module is designed to be completely generic and its receiving all the data its needs
to operate. The args function receives an object with the following properties:
Type
Action
SearchString
ConsumerKey ConsumerSecret Success
The string TWITTER
The string search tweets
Hashtag to search for, in our case Alloy.Globals.twitterHashTag
Alloy.Globals.twitterConsumerKey
Alloy.Globals.twitterConsumerSecret
Callback to execute on success

Table 6.1: Properties in the args variable


By structuring this function in this manner, we make sure that its selfcontained and that
we can later add our YouTube operations, while keeping the same architecture.
Weve created our socialfeeds.js module, and its designed not only to be generic and
independent, but itll also power our YouTube tab. To consume this module, well create
another module which well name conversationmod.js, will be stored in /lib along with the
rest of the modules. Listing 6.4 shows conversationmod.js.
Listing 6.4: conversationmod.js
function refreshList ( tableObject ){
require ( socialfeeds ) . getFeed ({
type : TWITTER ,
action : search_tweets ,
searchstring : Alloy . CFG . twitterHashTag ,
consumerKey : Alloy . CFG . twitterConsumerKey , consumerSecret : Alloy . CFG . twitterConsumerSecret , success : function ( response ){
fillTable ( response , tableObject );
},
error : function ( response ){
console . log ( response . data ) ;
}
})
}
function fillTable ( response , tableObject ) { try {
var created_at = tweet . created_at ;
var name = tweet . user . name ;
var screen_name = tweet . user . screen_name ;
var user_avatar = tweet . user . profile_image_url ; var url = https :// twitter . com / + screen_name + / status /
var data =[];
var parsed = JSON . parse ( response ); parsed . forEach ( function ( tweet ){
var id = tweet . id_str ;
var status = tweet . text ;
+ id ;

var row = {
id : id ,
status : status , created_at : created_at , name : name . trim () ,
screen_name : screen_name . trim () , user_avatar : user_avatar , url : url
}
data . push ( row );
})
var listItems = _. map ( data , function ( item ) { return {
avatar : { image : item . user_avatar }, name : { text : item . name } ,
screen_name : { text : @ + item . screen_name } , tweet : { text : item . status },
properties : {
url : item . url ,
id : item .id ,
screen_name item . screenname
}
};
}) ;

tableObject . sections [1]. setItems ( listItems );


if ( tableObject . sections [0]. items . length >0) {
tableObject . sections [0]. deleteItemsAt (0 ,1) ; }
} catch ( e){
alert (L( offline_error ) );
}
}
exports . refreshList = refreshList ;

In the code above you can see that were getting the data returned from Twitter and were
only grabbing a couple fields from it. To know which fields are available to you, simply
send the response to the console before parsing like so:
console . log ( response ) ;
var parsed = JSON . parse ( response );

Figure 6.7 shows the console response.

Figure 6.7: JSON


response displayed in the console
This JSON string can now be taken to jsoneditoronline.org for further examination, just
like we did with the JSON data in chapter 5. Figure 6.8 shows this object as displayed on

jsoneditoronline.org.

Figure 6.8: Looping


though Twitter results
Once weve extracted the data we need from the Twitter response, we now have a much
simpler object with only the fields we want to use.
{ id : 526261624064462849 ,
status : @thewarpedcoder @jhaynie do you have your # ticonnect
,
created_at : Sun Oct 26 06:38:43 +0000 2014 ,
name : TiDev ,
screen_name : user_avatar : tidevio ,
http :// pbs . twimg . com / profile_images /37851/7
f_normal . png ,
url : https :// twitter . com / tidevio / status /526261624064462849 }

Now, even though we have our data neatly formatted, we have it in a format thats using
the field names returned by Twitter. Whats more, even if you change the property names,
the ListView wont accept the data in this format.
ListView data needs to be formatted in a special way that matches the items we added to
the View. To convert this object into an object that is ListView-friendly, well use the map
function from underscore.js, which will accepts an array in one format, and will return it
in another.
var listItems = _. map ( data , function ( item ) {
return {
avatar
name
screen_name
},
tweet
properties : {
url
id
: { image : item . user_avatar } , : { text : item . name },
: { text : @ + item . screen_name
: { text : item . status } ,
: item . url ,
: item .id ,
screen_name : item . screenname }
};
}) ;

Underscore.js is a JavaScript library full of utility functions. Underscore comes built into

Alloy, so anytime you need to use an Underscore function, you simply call it by
prepending . to is, for example var x = .map(data,function). For more information about
Underscore.js, visit the official website at http: //underscorejs.org/
After calling the map function with our data array, weve successfully transformed our
data into the following format.
{
avatar : {
image : http :// pbs . twimg . com / profile_images /37851/7 f_normal . png
},
name : {
text : TiDev
},
screen_name : {
text : @tidevio
},
tweet : {
text : @thewarpedcoder @jhaynie do you have your # ticonnect
},
properties : {
url : https :// twitter . com / tidevio / status
/526261624064462849 ,
id : 526261624064462849
}
}

With the data in this format, we send it straight to the ListView. Figure 6.9 shows the
relationship of this data format with our ListView markup, explaining why we needed to
transform it.

Figure 6.9: Relationship of transformed object and ListView markup


Now our conversationmod.js is ready. To call these functions from our conversation.js
controller, we simply create a function to loadTweets, and while were at it, we implement
the refresh callback.
function dorefresh ( evt ){
loadTweets () ;
}
function loadTweets () {
if ( Ti . Network . online ){
if ($ . tweetlist . sections [0]. items . length ===0) {
$. tweetlist . sections [0]. insertItemsAt (0 ,[{
template : loadingtemplate ,
loading :{ text :L( refreshing ) }
}])
require ( conversationmod ) . refreshList ($ . tweetlist );
}
} else {

alert (L( offline_error ) );


}
}
loadTweets () ;

Weve successfully connected to Twitter, extracted data and have added it to our ListView.
We still have one little detail to take care of. As you can see in Figure 6.10, our iOS
version has a working refresh button in the TitleBar because we added it as part of the
Windows markup. Our Android version is missing this button.

Figure 6.10:
Missing refresh button on Android
ActionBar menu items are usually easy to add by simply using the <Menu >tag. The
challenge we have right now is that as opposed to iOS where the Titlebar belongs to the
Window, on Android the ActionBar belongs to the TabGroup. This means that the
TabGroup is the one that can add and remove buttons to the ActionBar. Additionally, in
our scenario, tab 0 and 1 have no buttons, while 2 and 3 need to have a Refresh button,
which are different to one another. We need to be able to change buttons and their
operations as the user changes tabs. We created the TabGroup in index.js, so lets go there
and make the necessary changes to account for this.
For more information on the <Menu >tag, used to add ActionBar menu items to non-tab
windows, refer to the official documentation at http://docs.
appcelerator.com/titanium/3.0/#!/api/Titanium.Android.Menu

6.2.3 Changing ActionBar Icons on Tab change


When youre working with stand-alone windows on Android, that is, that dont belong to
a tab, you set ActionBar items using a special <Menu >tag, which maps to
Titanium.Android.Menu. In a standalone scenario reacting to clicks or changing menu
items is handled from inside that windows controller.

When the Window is inside the tab, the procedure is different. In order to change
ActionBar icons for different Tabs, there are three things we need to know:
How to tell in which tab were on
How to remove any icons that are currently on the ActionBar
How to add icons that are relevant to the tab were currently on
Well start by creating a global variable that will keep the value of the current tab.
Remember, were doing all this inside index.js.
Alloy . Globals . currentTab =0;

Next well add an event listener to the focus event of the TabGroup, and from that event
well grab the index of the current tab, and in the process well use the Android
invalidateOptionsMenu function to tell Android that we want to change the menu items on
the ActionBar.
Alloy . Globals . tabGroup . addEventListener ( focus , function ( evt ) { if ( typeof evt . index !== undefined ) {
activity . invalidateOptionsMenu () ;
Alloy . Globals . currentTab = evt . index ;
}
}) ;

Every time you call invalidateOptionsMenu, Android will call the onCreateOptionsMenu
function, which will allow us to add options to the ActionBar. This function is empty by
default, so we simply need to add a callback to it.
invalidateOptionsMenu and onCreateOptionsMenu are not Titanium functions, but
Android functions. Remember that as a native framework, Appcelerator exposes to you
the functions of the native SDKs, and these two functions are part of the Android Activity.
You can read more about this in the Android official documentation at
http://developer.android.com/ guide/topics/ui/menus.html#options-menu
activity . onCreateOptionsMenu = function (e) { var item , menu ;
menu = e. menu ;
menu . clear () ;
switch ( Alloy . Globals . currentTab ){
case 2:
item = e. menu . add ({
title : L( refresh ) ,
showAsAction : Ti . Android . SHOW_AS_ACTION_ALWAYS , icon : / images / refresh . png
}) ;
item . addEventListener ( click , function (e) { if ( Ti . Network . online ){
if ($ . conversationTab . tweetlist . sections [0]. items . length ===0) {
$. conversationTab . tweetlist . sections [0]. insertItemsAt (0 ,[{
template : loadingtemplate ,
loading :{ text :L( refreshing ) }
}])
require ( conversationmod ) . refreshList ($ . conversationTab . tweetlist );
}
} else {
alert (L( offline_error ) );
}
}) ;
break ;
}

After adding this callback, you can run your app on Android and youll have a refresh
button on the ActionBar, showing only on the Conversation tab, as seen in Figure 6.11.

Figure 6.11: Android refresh button on ActionBar


Both the event listener and the onCreateOptionsMenu callback need to be added inside the
open callback we already have in index.js. Next, the only missing piece is responding to
clicks on the ListView.

6.2.4 Reacting to ListView clicks


As mentioned before, the click event listener for the ListView was added at the ListView
declaration level and not at the row level.
< ListView id = tweetlist onItemclick = doclick >

From our doclick callback, which lives inside conversation.js, we need to obtain the row
that was clicked, because inside this row we have added information about this tweet.
function doclick ( evt ){
var section var item = = $ . tweetlist . sections [ evt . sectionIndex ];
section . getItemAt ( evt . itemIndex ) ;
openApp ({ appUrl : twitter :// status ? id = + item . properties .id , webUrl : item . properties . url
}) ;
}

We now need to create the openApp function, which receives and object with two
properties: appURL, which is a URL using App URL Schemes, and the Web URL to this
Tweet. App URL Schemes are URLs that get registered on the device, which will allow
you to open other apps. In this case what were trying to do is open the actual Twitter app,
if it is installed, otherwise open the devices web browser. The OpenApp function looks as
follows.
function openApp ( obj ) {
if ( OS_ANDROID ){
Ti . Platform . openURL ( obj . webUrl );
} else {
if ( Titanium . Platform . canOpenURL ( obj . appUrl )) { Ti . Platform . openURL ( obj . appUrl );
} else {
Ti . Platform . openURL ( obj . webUrl );
}
}
};

As you can see from the code above, on Android we dont check for anything. The reason
for this is because Android will automatically open the App if it is already installed;
otherwise itll fallback to open the web browser. On iOS however, we have the
canOpenURL function, to which we send the App URL Scheme, and iOS will return True

if the App URL URL was reached. We then react accordingly by calling the openURL
function with either the appUrl or the webUrl.
To learn more about App URL Schemes, you can refer to http: //handleopenurl.com/. To
learn more about how to use them from Titanium, you can refer to
http://fokkezb.nl/2013/08/26/ url-schemes-for-ios-and-android-1/
Weve finished our Conversation tab. In this tab we learned how to connect to Twitter and
pull a list of tweets based on a given hashtag and add them to a ListView. We saw how
iOS Toolbar runs in the same context as the Window, so adding the refresh button was
straightforward. On Android however the ActionBar belongs to the TabGroup, so we had
to implement the icon switching at the TabGroup level. Finally we implemented an event
listener on the ListView, from which we grabbed the tweet id, constructed a Twitter URL
and called a function that will open the Twitter app if the app is installed or the web
browser if no app was found.

6.3 Working with Web Services


Its now time to implement our Videos window, in which well consume data from
YouTube web services. As youll see in this section, as opposed to Twitter where a special
library is needed, generally speaking, consuming Web will only require you to establish an
HTTP connection, and here well learn how to do it. Lets first start working on the visual
layout or our Videos screen.
This window is very similar in visual aspect as well as in its functionality, and since
weve created solid and modular foundation with our previous tab, youll see its very easy
to setup. Our expected result is shown in Figure 6.12.

Figure 6.12:
Expected results for Video Window
We start with the markup for our view, which is very similar to the Conversation window
< Alloy >
< Window id = video < RightNavButton class = container >
platform = ios >
< Button systemButton = Ti . UI . iPhone . SystemButton . REFRESH onClick = dorefresh / >
</ RightNavButton >
< ListView id = videolist onItemclick = doclick >
< Templates >
< ItemTemplate
< ImageView name = rowtemplate class = rowtemplate > bindId = thumb class = thumb / >
< Label bindId = summary
< Label bindId = author
class = summary / >
class = author / >
< Label bindId = duration class = duration / > </ ItemTemplate >
< ItemTemplate name = loadingtemplate class =
loadingtemplate >
< Label bindId = loading class = loading / >
</ ItemTemplate >
</ Templates > < ListSection < ListSection
</ ListView > </ Window >
</ Alloy >
name = notification / > name = videos / >

Just like we did with Twitter, well use the socialfeeds.js module, to which we need to add
a couple lines of code to make it work with YouTube. At the time of this writing, YouTube
requires no special library, API keys or authentication, at least not for reading data.

6.3.1 Connecting to Web Services

Connecting to Web Services and consuming data from them is something youll need to
do at one time or another. The process of connecting to YouTube is in fact no different to
that of communicating with any Web Service to which youd need to connect via HTTP.
Appcelerator provides an object called HTTPClient, which allows you to connect to any
web service via HTTP Protocol.
All we need to do is go to your getFeed function an extra case for YouTube.
case YOUTUBE :
var _url = https :// gdata . youtube . com / feeds / api / users /# USER #/ uploads ? max - results =# MAX #& alt = json ;
var url = _url ;
url = url . replace ( # USER # , Ti . Network . encodeURIComponent ( args . user )) ;
if ( args . max >0) {
url = url . replace ( # MAX #, args . max ) ;
} else {
url = url . replace ( # MAX # , 20 ) ;
}
var http = Ti . Network . createHTTPClient ({ onload : args . success ,
onerror : args . error
})
http . open ( GET , url ); http . send () ;

This function was fairly easy to implement because its following the same architecture we
laid out before. Just like before, we want to make it easy to change data going forward, so
lets add the YouTube user as a global variable in config.json.
global : {
venueAddress : 747 Howard St , San Francisco , CA
94103 ,
venuePhoneNumber : + (415) 974 -4000 ,
twitterHashTag : # tidev ,
twitterConsumerKey : the_given_key ,
twitterConsumerSecret : the_given_secret ,
youtubeUser : appcelerator
}

Now that we have our socialfeeds.js function working with YouTube, lets create a new
module for our videos. Create an empty file in /lib named videomod.js. This file will have
the exact same structure as conversationmod.js. We start with the refreshList function. In
this case were calling YouTube for a specific user, so well specify the YOUTUBE type.
function refreshList ( tableObject ){
require ( socialfeeds ) . getFeed ({
type : YOUTUBE ,
user : Alloy . CFG . youtubeUser ,
max : 20 ,
success : function (e ){
fillTable ( this . responseText , tableObject );
},
error : function (e ){
console . log ( this . responseText ) ; }
})
}

The fillTable function, again, is very similar to the one used for Twitter.
function fillTable ( response , tableObject ) {
try {
var data =[];
var parsed = JSON . parse ( response );
parsed . feed . entry . forEach ( function ( video ){
var link = var summary = var author = var duration = var thumb =
;
var row ={
link : summary : author : duration : thumb :

}
data . push ( row ); video . link [0]. href ;
video . title . $t ;
video . author [0]. name . $t ;
video . media$group . yt$duration . seconds ; video . media$group . media$thumbnail [0]. url
link ,
summary ,
author ,
convertMS ( duration *1000) , thumb
})
var listItems = _. map ( data , return {
thumb : summary : author : duration :
text : item . duration .h + : + item . duration .m + : + item . duration .s },
properties : { url : item . link }
};
}) ;
function ( item ) {
{ image : item . thumb }, { text : item . summary }, { text : item . author } , {
tableObject . sections [1]. setItems ( listItems ); if ( tableObject . sections [0]. items . length >0) { tableObject . sections [0]. deleteItemsAt (0 ,1) ;
}
} catch ( e){
alert (L( offline_error ) );
}

YouTube returns video duration in milliseconds. To convert it into a friendlier format, Ill
used a function I call convertMS, which will essentially take the integer number that
represents milliseconds, will perform several math functions on top of it, and will return
an object with values for days, hours, minutes and seconds.
function convertMS ( ms ) {
var d , h , m , s ;
s = Math . floor ( ms / 1000) ;
m = Math . floor (s / 60) ;
s = s % 60;
if ( parseInt (s ) <10) s = 0 + s;
h = Math . floor (m / 60) ;
m = m % 60;
if ( parseInt (m ) <10) m = 0 + m ;
d = Math . floor (h / 24) ;
h = h % 24;
return {
d : d , h : h , m : m , s : s
};
};

Just like we did before, we can use jsoneditoronline.org to inspect the data returned by
YouTube. Figure 6.13 shows where the data is located within the response object.

Figure 6.13: How to get videos from YouTube feed


Our fillTable function above is looping through all the records and is extracting only the
relevant data, returning and array of objects with the following format.
{
link : https :// www . youtube . com / watch ? v= ur00xMmNU & feature = youtube_gdata ,
summary : Making the Mobile Mind Shift : A Forrester ,
author : Appcelerator ,
duration : {
d : 0 ,
h : 0 ,
m : 54 ,
s : 56
},
thumb : https :// i. ytimg . com / vi / ur00xDMMmNU /0. jpg

We then perform the transformation with the map function, and get a ListView friendly
object as seen below.

{
thumb : {
image : https :// i. ytimg . com / vi / ur00xDMMmNU /0. jpg },
summary : {
text : Making the Mobile Mind Shift : A Forrester },
author : {
text : Appcelerator
},
duration : {
text : 0:54:56
},
properties : {
url : https :// www . youtube . com / watch ?v = ur00xDmNU & feature = youtube_gdata
}
}

After transforming the data, we have it ready in ListView-friendly format, as seen in


Figure 6.14.

Figure 6.14:
Relationship for transformed object and ListView markup
Now to call these functions from the videos.js controller, we do as before.
function dorefresh ( evt ){
loadVideos () ;
function loadVideos () {
if ( Ti . Network . online ){
if ($ . videolist . sections [0]. items . length ===0) {
$. videolist . sections [0]. insertItemsAt (0 ,[{ template : loadingtemplate , loading :{ text :L( refreshing ) }
}])
require ( videomod ) . refreshList ($. videolist ) ; }
} else {
alert (L( offline_error ) );
}
}
loadVideos () ;

6.3.2 Changing ActionBar Icons on Tab change


Weve already set the ground for this when we worked with Twitter. Now we simply open
index.js and add an additional case for tab number 3.
case 3:
item = e. menu . add ({
title : L( refresh ) ,
showAsAction : Ti . Android . SHOW_AS_ACTION_ALWAYS ,
icon : / images / refresh . png
}) ;
item . addEventListener ( click , function (e) {

if ( Ti . Network . online ){
if ($ . videosTab . videolist . sections [0]. items . length ===0) {
$. videosTab . videolist . sections [0]. insertItemsAt
(0 ,[{
template : loadingtemplate ,
loading :{ text :L( refreshing ) }
}])
require ( videomod ) . refreshList ($. videosTab . videolist ) ;
}
} else {
alert (L( offline_error ) );
}
}) ;
break ;

6.3.3 Reacting to ListView clicks


This section also builds on top of the foundation created with the Conversation tab. From
our doclick callback, which lives inside videos.js, we need to obtain the row that was
clicked, because inside this row we have added information about this tweet.
function doclick ( evt ){
var section var item = = $ . videolist . sections [ evt . sectionIndex ];
section . getItemAt ( evt . itemIndex ) ;
openApp ({ appUrl : webUrl :
}) ;
item . properties . url , item . properties . url
}

The openApp function also suffers little changes, as seen below.


function openApp ( args ) {
if ( OS_ANDROID ){
Ti . Platform . openURL ( args . webUrl );
} else {
if ( Titanium . Platform . canOpenURL ( args . appUrl )){ Ti . Platform . openURL ( args . appUrl );
} else {
Ti . Platform . openURL ( args . webUrl );
}
}
};

This completes our Videos tab, the last piece of our Conference app congratulations!. Just
like I mentioned before, Im not including the stylesheets, as they have nothing special
except positioning and styling of the row elements. Make sure you check them in the
companion source code.

6.4 Summary
This chapter concludes the code for the Conference app we started in chapter 4. In the
process weve worked several important topics that will apply to all your apps.
Changing ActionBar menu times on tab change
When working with single-window apps on Android, its easy to add ActionBar menu
items by using the <Menu >tag. When working with Tabs however, the 6.4. Summary
ActionBar doesnt belong to the individual window, but to the tab group. In order to
change icons, we need to set an event listener to the focus event of the tab group, and from

this event grab the currently select tab. Then using this tab number, we can add menu
items to the ActionBar, first calling the invalidateOptionsMenu, and then setting a
callback on the onCreateOptionsMenu method of the Android Activity.
ListViews
The ListView component was designed to overcome the performance issues that could rise
from creating complex TableViews. With ListViews, you first create ListView Templates
that define the contents of each row, and then create an Array of data that includes the
template to be used by each row. Underneath, Titanium will request all the rows at once
from the native SDK, resulting in a dramatic increase of your lists performance.
Connecting to Twitter
Twitter has a very strict security model, which requires you to formally create a Twitter
app and obtain API keys that will allow you to connect to the service. Since implementing
the necessary secure connections is not trivial, we used the codebird.js third-party library,
connected to Twitter, obtained the data in JSON format, which we then used to display in
a ListView.
Web Services
Generally speaking, web service consumption starts with an HTTP call. In this chapter we
consumed data from YouTube, using Titaniums HTTPClient Object. From this library we
called YouTube, received the JSON response, we parsed it and displayed it using a
ListView.
Opening other apps
We explored briefly the concept of App URL Schemes, and we used it to open the native
Twitter app. We also saw how all this is done by using Titaniums openURL method,
which not only works for opening other apps, but also to open a web browser pointing to a
desired page.
In chapter 7 well build an app that uses the devices camera, takes a picture, performs
some changes to it, and then allows you to share it with social networks.

Chapter 7

Working with the Camera and native


sharing with social networks
This chapter covers:
Using the camera
Using custom fonts
Creating dialogs
Working with transparent backgrounds
Creating images from views
Using CommonJS to normalize platform-specific functions
Cross-platform social sharing
Splash screens and app icons
In this chapter well be creating a very cool app, that although simple, its actually kind of
neat. With this app your user will be able to take a picture, add some text to it, merge that
text onto the picture effectively creating a meme, and then share it with Facebook and
Twitter.
In the process of building the app well see how to take pictures, which in Titanium is
extremely easy using the function Titanium.Media.showCamera(). Well also work with
custom fonts and transparent background, this last one though sounds trivial, is actually
kind of tricky because you have to express your transparency using a format known as
ARGB (Alpha, Red, Green, Blue).
In two different instances well be creating CommonJS modules as a way of normalizing
platform-specific code, a process that I recommend you follow in your own code in order
to keep it modular and easy to read.
The core of this chapter, besides working with the camera, is the methods for sharing text
and images with social networks. Here youll see how Android has an os-provided
mechanism for this named Share Intent. iOS however, even when it does have such a
mechanism, its not exposed to the Titanium core API, but well implement it using a
third-party module named TiSocial.Framework.
Last but not least, well learn how to change your apps icon and splash screens, a process
that though Im leaving it to the end, should really be as important as the app itself.
I encourage you to make some changes to the app, change the name and go ahead and
submit it to the Google Play and Apple App Store. If youre just starting out, youll have
one app in your catalog right away. This chapter will go at faster pace because you already
know the basics.

7.1 What well build


Were going to build a MEME Generator, which well call PhotoMEME. From this app,
the user will be able to take a picture, add some text to the top and/or bottom of it, and
then share it through social networks. Figure 7.1 shows a wireframe mockup of our
expected results.

Figure 7.1: Wireframe representation of our app


The first screen of the app will show a big button to invoke the camera. This button will
show the camera and after the picture is taken, the app will provide a button to share the
picture with social networks. This button will invoke the native mechanism provided by
the device for sharing images.
Just like we did with the Conference App, well make this one languageaware, so well
make sure that all texts and captions are stored in language files. Having the wireframe,
we then need to analyze the platform-specific implementation details, so lets look at the
app screen by screen, first from product feature standpoint, and then well jump into the
code.

7.1.1 The main app screen


Ill show you the different screens of the app, and Id like you to look at how the screens
look similar, but different. The main screen (Figure 7.2) will have 3 main components:
A help button, which will simply show a short message about the app, more like an about
box.
A big button for launching the devices camera
A short message instructing the user to take the picture in portrait mode.

Figure 7.2: Main


screen
The reason for the disclaimer is simplicity. Memes are most of the times created to be
shared on social networks and are more often than not viewed in mobile devices, so by
keeping everything in portrait mode not only were making it easier for us, but also for the
user.

7.1.2 Editing the picture


Once the photo is taken, well display it in a second screen with the photo that was taken
(Figure 7.3). From this screen the user could decide to go back to the previous screen and

re-take the photo.


Figure 7.3: Photo taken and ready for editing
As you see in the Figure above, the Android version is showing the ActionBar with the
apps icon and the up caret to go to the previous screen, while the iOS version shows a
close button. Well see in the code how to enable this platform-specific difference. Also in
that top area well be displaying the native sharing icon, which Ill explain shortly. Notice
that just like before, both versions look similar but different. There are some elements of
branding in the color scheme, but items are shown in their own platform-specific way.
The screen will provide two text areas, one on the top and one on the bottom. By tapping
on any of these text areas, a dialog box will be shown to edit the text (Figure 7.4).

Figure 7.4: Enter text


These two dialogs are created in two different ways, so well be building a reusable
module to which well send the title, the text of the Close button and a callback function
to execute once the dialog is dismissed.

7.1.3 Generating the meme and sharing with social networks


When the share icon is clicked well call a Titanium function called toImage, which will
merge the text onto the picture that was taken, and will return a brand new picture. While
this happens, well show the corresponding platform progress indicator (Figure 7.5),
another important element for bringing native user experience.

Figure 7.5: Generating Meme


Once we have this picture ready, well see the specifics of how sharing works on iOS and
Android (Figure 7.6).

Figure 7.6: Sharing


Meme with Social Networks

Sharing on Android is a system-provided feature called Share Intent. iOS however


works differently, so well be using a third-party module that exposes this native
functionality to Titanium. To keep the code clean and modular, well use a CommonJS
wrapper to which we simply send the image and the text to share, and itll take care of the
cross-platform differences.

7.2 Setting up the app


Lets start setting up our app. Begin by creating a new project and name it PhotoMEME.
Then, create an ActionBar Style with color #282828 and Dark as your base theme.
Download the assets file and apply it to your app. You may want to go back to Chapter 4
and review the details of how to use the ActionBar Style Generator located at
http://jgilfelt.github.io/ android-actionbarstylegenerator.
This app will only have two windows, and the first one is index, so lets go ahead and
create the second Window named edit, either through the Studio menus or by typing:
alloy generate controller edit on your terminal/command prompt.
This screen, shown in Figure 7.7 is relatively simple. The only platformspecific part of it
is the way the help button is provided. On Android we have the ActionBar so we put the
button there. On iOS is up to us, so I decided to place it in the topright corner.

Figure 7.7: Main


Screen
Given that there are only three elements, the markup is easy as you can see in listing 7.1
below.

Listing 7.1: index.xml


< Alloy >
< Window class = container >
< Button class = helpbutton platform = ios onClick = showinfo / > < Menu id = menu platform = android >
< MenuItem id = info onClick = showinfo />
</ Menu >
< Button id = start onClick = doClick / >
< Label id = portrait_tip / >
</ Window > </ Alloy >

Just like weve done in previous chapters, all styling and positioning details are in the
stylesheet, giving you the flexibility of changing them without disrupting the actual screen
markup. Listing 7.2 shows index.tss.
Listing 7.2: index.tss
. container [ platform = ios ]: {
orientationModes : [ Ti . UI . PORTRAIT ],
backgroundColor :#282828 ,
statusBarStyle : Titanium . UI . iPhone . StatusBar . LIGHT_CONTENT }
. container [ platform = android ]: { orientationModes : [ Ti . UI . PORTRAIT ], backgroundColor :#282828
}
# start :{
height :300 ,
width :300 ,
backgroundImage :/ photobtn . png ,
backgroundSelectedImage :/ photobtn_dn . png
}
# portrait_tip :{
text : L( portrait_tip ) ,
width : Ti . UI . FILL ,
height : Ti . UI . SIZE ,
textAlign : Ti . UI . TEXT_ALIGNMENT_CENTER , color :# fff ,
bottom :20
}
# info :{
title : Info ,
showAsAction : Ti . Android . SHOW_AS_ACTION_ALWAYS , icon : Ti . Android . R. drawable . ic_menu_help
}
. helpbutton :{ top :30 , right :5 , backgroundImage :/ images / helpicon . png , width :30 ,
height :30 }

Make sure you check the companion code for the graphical assets used for the help icon
on iOS and the big button in the center, for which we have two versions: pressed and
unpressed.

7.2.1 Implementing functionality


Its time now to work with index.js to implement the functionality for this screen. There
are some interesting concepts here, so lets build the code step-by-step. To begin, lets
create three global entries in alloy.js.
var by =L( created_using ) ;
Alloy . Globals . byline = ( Ti . Platform . osname === android ) ? by + Android : by + iOS ;
Alloy . Globals . bookurl = http :// buildmobileapps .io ;

This example is showing the app as it was submitted to the App Store and Play Store,
which use the help icon to promote this book. When you build the app for yourself, you
wont need the bookurl variable or any other reference.
Now, open your index.js and lets start creating the methods we need; well start with the

easiest one, the showinfo callback executed when the user clicks on the help icon.
function showinfo ( evt ){
var dialog = Ti . UI . createAlertDialog ({
message : String . format (L ( about ) , Alloy . Globals . bookurl ) , cancel : 1,
buttonNames : [L( book_btn ) , title : L ( about_title )
})
dialog . addEventListener ( click , if (e . index === 0) {
Ti . Platform . openURL ( Alloy . Globals . bookurl ); }
}) ;
dialog . show () ;
L( close_btn ) ],
function (e ){

Figure 7.8: Help


dialog
The code above will create and display the dialog shown in Figure 7.8. Notice that the text
alignment differs across platforms. This is the expected behavior and cant be changed.
Notice also that iOS shows the Close button as the second button, while Android shows it
first. This again, is handled by the operating system to ensure consistency across all the
apps within the platform. These differences should be embraced and I suggest you dont
try to create a custom dialog just so it looks the same on both platforms.
Next, lets take care of taking the photo itself. To keep the code organized and portable,
well be implementing this method as a separate module that well call photomod.js,
shown in listing 7.3, which should live in your /lib folder.
Listing 7.3: photomod.js
function takePhoto ( success , fail ){
var img = null ;
Titanium . Media . showCamera ({
success : function ( event ) {
if ( OS_ANDROID ){
img = require ( imgfix ) . rotateAndResize ( event . media ,640 ,80) ;
} else {
img = event . media ;
}
success ( img );
},
error : function ( error ) {
fail ( error );
},
mediaTypes : [ Ti . Media . MEDIA_TYPE_PHOTO ]
}) ;
}

exports . takePhoto = takePhoto ;

The code above calls the Titanium showCamera method, which is a crossplatform
function that shows the camera and returns the picture that was taken. The usage of this
function is simple and straightforward. We however need to take care of one important
Android detail, which you can see in the line that calls the rotateAndResize method.
The problem were solving is that because of the diversity of Android devices, there are
some obscure ones that do not properly return the data that specifies the orientation in
which the photo was taken. On top of this, newer Android devices take pictures in such
high resolution, that the file size makes the device go out of memory when trying to
display it on the screen. At the time of this writing, heres no Titanium-provided
mechanism to fix the orientation problem, so well be using a native module, which well
access through the wrapper function shown in listing 7.4. If in the future Titanium
provides this functionality, simply change the line that calls the imgfix so it is just like the
iOS one.
Listing 7.4: imgfix.js
function rotateAndResize ( media , width , quality ) {
var moment
var utilsModule
= require ( alloy / moment ) ;
= require ( com . alcoapps . imageutility ) ;
var dataDirectory
() ;
var fileName
= Ti . Filesystem . getApplicationDataDirectory
= String . format ( Company_Photo_ % s. jpg , moment () . format ( YYYY -MM -DD -HH - mm -ss - SSS -ZZ ) ); var file
fileName ) ;
var fileNativePath = Ti . Filesystem . getFile ( dataDirectory ,
= file . nativePath ;
file . write ( media ); file = null ;
utilsModule . rotateResizeImage ( fileNativePath , width || 640 , quality || 80) ;
media = Ti . Filesystem . getFile ( fileNativePath );
return media ; exports . rotateAndResize = rotateAndResize ;

The rotateAndResize function receives the original photo, the desired destination width
and the desired compression ratio. This function is a wrapper that simply creates a
temporary file handle, which is then sent to the native module, which takes care of all the
complex details on the native level. After the module has run, the new image is returned to
the caller. The native module is free and open source, and can be downloaded from
https://github.com/ricardoalcocer/AndroidRotateImage and placed in your modules folder,
and the imgfix.js file should live in your /lib folder.
Now that we have created our modules for taking and fixing the picture, were ready to go
back to index.js and implement the doClick callback that is executed when the camera
button is pressed.
var cb_success = function ( img ){
Alloy . createController ( edit ,{ image : img }) . getView () . open () ; }
var cb_fail = function ( err ){
if ( err . code == Titanium . Media . NO_CAMERA ) { console . log ( No Camera ) ;
} else {
console . log ( Fail ) ;
}
}
function doClick ( e) {
require ( photomod ) . takePhoto ( cb_success , cb_fail ) ;
}
$. index . open () ;

In the code above we define the two callbacks, required by the takePhoto method we
created earlier. Once the picture was taken successfully, the cb success function will
receive the image, which will be sent to the edit controller and the edit window will be
opened.

7.2.2 After taking the picture


Once the picture has been taken, the edit controller will be opened. This screen is where
all the magic happens. Remember that our objective is to be able to add text to the picture
and create a new image from that combination of elements. In order to understand how
well achieve this, lets look at Figure 7.9 that shows how we need to organize our
elements on the screen.

Figure 7.9: How components are laid out on the screen


Well have a main container (a view) that well call meme. This container will hold all
the other elements. The first element well add is the photo itself (an ImageView), which
came from the previous window. To the top well add a label that well call memetoptext,
and well do the same at the bottom with another label called memebottomtext. Finally,
well add another label that will show the byline we stored in alloy.js. Listing 7.5 below
shows the full markup.
Listing 7.5: edit.xml
< Alloy >
< Window id = edit class = container >
< ActionBar id = actionbar platform = android / >
< Menu id = menu platform = android >
< MenuItem id = closeitem onClick = btnshare / >
</ Menu >
< Toolbar id = toolbar platform = ios >
< Items >
< Button id = closebtn onClick = doclose / >
< FlexSpace / >
< Label color =# fff > Preview </ Label >
< FlexSpace / >
< Button id = sharebtn onClick = btnshare / >
</ Items >
</ Toolbar >
< View id = meme >
< ImageView id = thephoto / >
< Label id = memetoptext class = caption onClick = edittop / >
< Label id = memebottomtext class = caption onClick = editbottom / >
< Label id = byline / >
</ View >

< ProgressIndicator ns = Ti . UI . Android id = progressIndicator platform = android / >


</ Window >
</ Alloy >

Notice that weve added the ActionBar for Android and a Toolbar for iOS. This will
provide the native structure needed to share the image and close the window, as shown in
Figure 7.10.

Figure 7.10: The photo has been taken


The stylesheet for this screen is pretty standard, so Ill leave it to you to explore it from the
companion code. Id like however to call out the Tap to edit text, which is contained in a
transparent bar. This is achieved by applying the following style.
. caption :{
font :{
fontSize : 38 ,
fontFamily : Impact ,
fontWeight : bold
},
color : # fff ,
shadowColor : #000 ,
shadowOffset : 15 ,
shadowRadius : 20 ,
textAlign : Ti . UI . TEXT_ALIGNMENT_CENTER , width : Ti . UI . FILL ,
backgroundColor : #40000000
}

For the background color Im using an 8 digit HEX number instead of the regular 6, or 3
depending on the case. This is actually a transparent black, so the last 6 digits are in fact
the normal representation of black, 000000. The first two digits, in this case 40, represent
20% of opacity, causing the background to be shown transparent. This is called ARGB

(Alpha, Red, Green, Blue), providing 2 digits for the Alpha channel, 2 for Red, two for
Green and two for blue. The opacity has to be provided as HEX values, so see the Table
7.1 for possible opacity values. This is the recommended crossplatform way of applying
transparent colors to Titanium.
100% FF 45% 73
95% F2 40% 66
90% E6 35% 59
85% D9 30% 4D
80% CC 25% 40
75% BF 20% 33
70% B3 15% 26
65% A6 10% 1A
60% 99 5% 0D
55% 8C 0% 00
50% 80

Table 7.1: HEX Opacity Values Background colors can be provided as either HEX triplets
or Red, Green and Blue sets like rgb(255,0,0). If using the latter, you could specify
transparency by calling rgba(255,0,0,1.5), where the last number is the value for the Alpha
Channel. Its important to keep in mind however that should you use rgba, the Alpha
Channel on iOS is expressed as a number between 0 and 1, while on Android is expressed
as a number between 1 and 255.
Also in that snippet you can see that Im using a custom font, Impact. Using custom fonts
is as easy as simply naming them in you stylesheet. Youll have to ship that font with your
app though, and you do this by creating a folder named font inside your assets folder, as
seen in Figure 7.11.

Figure 7.11:
Custom fonts
Add your custom fonts to this folder, keeping in mind that theyll increase the apps file
size. For more information about using custom fonts, refer to the official documentation at
http://docs.appcelerator.com/titanium/3.0/#! /guide/Custom_Fonts.
Once we have our markup and styling, lets start working on the controller that
implements the functionality for this window.

7.3 Adding text to the image


Go ahead and open up edit.js and lets start adding code to it. Well start with the easy,

shown below.
var args = arguments [0] || {};
var thisWin = $ . edit ;
$. byline . text = Alloy . Globals . byline ;
$. thephoto . image = args . image ;
function doclose () {
thisWin . close () ;
}

In the code above we create a variable to hold a pointer to this window for easier access
later. We also grab the byline from the Alloy globals and the photo that came as payload
from the previous window. We also implement the first method, the close button, which
simply closes the Window.
Next, lets take care of editing the text, which should work as seen in Figure 7.12.

Figure 7.12:
Editable areas and dialog boxes
If you remember from edit.xml, we added click events to the text labels. < Label id = memetoptext
class = caption onClick = edittop / > < Label id = memebottomtext class = caption onClick = editbottom / >

These two callbacks will open the dialogs that will be used to edit the text. However, the
way these dialogs are constructed differs between platforms, so well be creating a
CommonJS module that will wrap this functionality for us, allowing us to keep the code
easy to read, as seen below.
function edittop ( evt ){
require ( editdialog ) . show ({
hint : L( enter_text ) ,
closeButton : L ( close_btn ) ,
callback : function ( text ){
$. memetoptext . text = text ;
}
}) ;
}
function editbottom ( evt ){
require ( editdialog ) . show ({
hint : L( enter_text ) ,
closeButton : L( close_btn ) ,
callback : function ( text ){
$. memebottomtext . text = text ; }
}) ;
}

As you can see from the code above, the editdialog module, which well be building
shortly, will make your code clean and simplified, leaving all the platform-specific code
out of the main logic of your controller. By using this technique, youre actually
increasing your code reusability, as your app code remains constant, and all platform-

specific changes are handled by an external module. Lets look at how to build this
module.

7.3.1 Cross-platform dialog


To implement the dialog box well again Titanium createAlertDialog method. This time
around well be using an additional property that allows us to add a text field to the dialog.
It is configured differently on iOS and Android, so Ill show you how each one works, and
then well build the generic module. Lets start with the iOS version shown below.
var dialog = Ti . UI . createAlertDialog ({
title : DESIRED TITLE ,
style : Ti . UI . iPhone . AlertDialogStyle .
PLAIN_TEXT_INPUT ,
buttonNames : [ ARRAY ,OF , BUTTON , TITLES ] ,
cancel : 0
}) ;
dialog . addEventListener ( click , function (e ){
if (e . index !== e. source . cancel ){
}
}) ;
dialog . show () ;

This code will effectively display the dialog on iOS showing a text field and the specified
buttons. At the moment of executing the event listener, the text that was entered will be
returned to us in the text property of the event object, in this example e.text. Lets now
look at the Android version of this dialog.
var textfield = Ti . UI . createTextField ({
height : Ti . UI . FILL ,
width : Ti . UI . FILL
}) ;
var dialog = Ti . UI . createAlertDialog ({
title : DESIRED TITLE ,
androidView : textfield ,
buttonNames : [ ARRAY ,OF , BUTTON , TITLES ] ,
cancel : 1
}) ;
dialog . addEventListener ( click , function (e ){
if (e . index !== e. source . cancel ){
}
}) ;
dialog . show () ;

In the Android version above, we need to create a TextField and then add it to the
androidView property of the AlertDialog object, which will effectively embed this text
field into the dialog. When the event listener is executed, the value will be returned to us
in the value property of object that was provided as androidView, in this example
e.source.androidView.value.
This code could easily be added to the controller in an if block. However, I always try to
create modules for platform-specific code like this one for two reasons: first, the code ends
up being more readable, and second because it allows me to perform any additional
change in the module without actually touching my controller code. This is however a
decision that has to do with your coding style, and has no real effect in how Titanium
behaves.

Now that you know how the iOS and Android dialogs work, lets look at how we want to
be able to call them. We want to be able to make the same call regardless of the platform,
for example:
require ( editdialog ) . show ({
hint : L( enter_text ) ,
closeButton : L ( close_btn ) ,
callback : function ( text ){
$. memetoptext . text = text ; }
}) ;

Listing 7.6 shows the integrated module, which you should save to /lib. The main
function, called show, receives a variable named args, which is an object that contains
the properties: hint, closeButton and callback. Once it runs, itll take care of the rest.
Listing 7.6: editdialog.js
function show ( args ){
if ( OS_IOS ){
var dialog = Ti . UI . createAlertDialog ({
title : args . hint ,
style : Ti . UI . iPhone . AlertDialogStyle .
PLAIN_TEXT_INPUT ,
buttonNames : [ args . closeButton ,OK ] , cancel : 0
}) ;
dialog . addEventListener ( click , function (e ){ if (e . index !== e. source . cancel ){
args . callback (e. text ) ;
}
}) ;
dialog . show () ;
} else {
var textfield = Ti . UI . createTextField ({
height : Ti . UI . FILL ,
width : Ti . UI . FILL
}) ;
var dialog = Ti . UI . createAlertDialog ({
title : args . hint ,
androidView : textfield ,
buttonNames : [ OK , args . closeButton ],
cancel : 1
}) ;
dialog . addEventListener ( click , function (e ){
if (e . index !== e. source . cancel ){
args . callback (e. source . androidView . value ); }
}) ;
dialog . show () ;
}
}
exports . show = show ;

Weve implemented the text editing and the close button of this window.
Whats left to implement is the sharing action.

7.3.2 Sharing your image


Sharing images with social networks, or other apps for that matter, its much easier on
Android than on iOS. Android has a built-in mechanism called Intents, which is used to
perform communication between apps. The official documentation for using Intents with
Appcelerator is located at http://docs.
appcelerator.com/titanium/3.0/#!/api/Titanium.Android.Intent, where you can find many
different examples of Android Intents. However, the one we care about is the Share
Intent.

If youve used Android before, youve seen the Share Intent dialog in Figure 7.13.

Figure 7.13: Sharing


dialog on Android
The dialog above is consistently shown by any app that allows you share data with another
apps. By invoking it, Android will assemble a list of all the installed apps that can handle
the data youre trying to send, so the list of apps will differ from user to user. Appcelerator
exposes the native calls from the SDK, and to share a text status and an image youd use
the code below, with is in many ways similar to the way youd do it in Java.
var intent = null ;
var intentType = null ;
intent = Ti . Android . createIntent ({
action : Ti . Android . ACTION_SEND # A
}) ;
intent . putExtra ( Ti . Android . EXTRA_TEXT , TEXT_TO_SHARE ) ;
intent . type = image /*;
intent . putExtraUri ( Ti . Android . EXTRA_STREAM , THE_IMAGE );

Ti . Android . currentActivity . startActivity ( Ti . Android .


createIntentChooser ( intent , WINDOW_TITLE ) ;

The above code snippet takes care grabbing the given text and image, and sharing it with
the app the user selects from the sharing dialog. Well be using this code in a module that
well create shortly, but first, lets see how this works on iOS.
iOS has a native object called UIActivityViewController which is equivalent to Androids
share intent dialog. The Titanium core SDK however doesnt currently expose it, so in
order to use it we need to rely on a module. The module well be using is free and Open
Source, and can be found at https: //github.com/viezel/TiSocial.Framework. Go ahead and
download the latest version and save it to your /modules folder, just like you did in
Chapter 4 with the ViewPager module. Dont forget to also add it to your tiapp.xml as:
< modules >
< module platform = ios > dk . napp . social </ module >
</ modules >

Now, just like we did with the editdialog, I have created a CommonJS module that wraps
both the Android Sharing Intent and the TiSocial.Framework module. The module is
called com.alcoapps.socialshare and can be downloaded from
https://github.com/ricardoalcocer/socialshare. Download it and drop it in your /lib folder.
Now that weve explored the details of how to share text and images with social networks
and we have all of our modules in place, were almost ready to implement the function
that actually shares our meme. Before we get to it, we need to add another third-party
module, this one in a form of an Alloy Widget. If you remember from chapter 3 where we
looked at Alloy Widgets, there are different sources to find pre-made Widgets to be used
in your apps. In this app well be using a Widget called nl.fokkezb.loading. This Widget
will provide us with a nice progress dialog to be used in the iOS version of our app.
Download the Widget from https://github.com/FokkeZB/nl.fokkezb.
loading,andsaveittoapp/widgets. Then remember to open your config.json file and add the
Widget as a dependency.
dependencies : {
nl . fokkezb . loading :*
}
require ( com . alcoapps . socialshare ) . share ({ status
image
androidDialogTitle })

Having done this, go to index.js and add the following line to the top of the controller.
Alloy . Globals . loading = Alloy . createWidget ( nl . fokkezb . loading ) ;

This line runs as soon as you run your app, and creates a global instance of the widget, so
it can be used from any screen. Well be using this Widget for our iOS version, because as
you remember, in our edit.xml file we added a tag for the Android Progress Indicator with
the line seen below.
< ProgressIndicator ns = Ti . UI . Android id = progressIndicator platform = android / >

We are now ready to create our function to share the image, which well add to edit.js.
function btnshare ( evt ){
var meme = fileToShare = null ;
if ( OS_ANDROID ){
$. progressIndicator . show () ;
} else {
Alloy . Globals . loading . show (L ( generating ) , false ) ; }
setTimeout ( function () {

if ( OS_ANDROID ){
meme = $. meme . toImage () . media ;
fileToShare = Titanium . Filesystem . getFile ( Titanium .
Filesystem . externalStorageDirectory , tmpmeme . jpg ) ; } else {
meme = $. meme . toImage () ;
fileToShare = Titanium . Filesystem . getFile ( Titanium .
Filesystem . applicationDataDirectory , tmpmeme . jpg ) ; }
fileToShare . write ( meme ) ;
if ( OS_ANDROID ){ : L ( signature ) ,
: fileToShare . nativePath , : L( android_share_dialog )
$. progressIndicator . hide () ; } else {
Alloy . Globals . loading . hide () ; }
} ,200)
}

In the code above you can see that we are conditionally showing and hiding the progress
indicators depending on the platform, effectively showing native progress bars as seen in
Figure 7.14.

Figure 7.14:
Platform-specific progress indicators
Were then wrapping our code in a JavaScript setTimeout function, configured for 200
milliseconds. The reason for doing this is that the toImage function runs synchronously,
potentially blocking the UI for a couple ticks. If we run toImage right after showing the
progress indicators, we risk the UI being briefly blocked before the indicator is shown,
causing that we dont see it at all.
We then make sure we get the right image, because on Android the image is returned in
the media property. We write the image to a temporary file, and then call the share method
to which we send the nativePath to the temporary file. By running the share method, the
module will show the native sharing window for the platform in which were running, as
seen in Figure 7.15.

Figure 7.15: Crossplatform sharing


After we call the share method, controlled is passed over to the native functions, so from
here on out, everything is handled by the operating system. This concludes the app, which
though simple, is fun and full of useful features Im sure youll use on many apps.
One last detail we havent seen in any previous chapter is how to modify your app icon
and splash screens, so lets learn how to do just this.

7.3.3 Adding the App Icon and Splash Screen


Even when I have left this topic to the end of the book, Id like to emphasize that the
Splash screen, and specially the app icon are the first thing your user sees, and could very
well determine if a user downloads your app or not. Creating your app icon is almost as
important as coding the app itself and special care should be taken when creating it.
There are many guides about how icons should be designed, and as youd expect by now,
iOS and Android icons are different. Look at Figure 7.16.

Figure 7.16: App


icons on iOS and Android
The biggest difference between iOS and Android icon design is that all iOS icons are
enclosed in a square with rounded corners, which by the way is provided by the operating
system itself to keep consistency across all apps. Android icons on the other hand, are
transparent and could be of different shapes, giving you more liberty in your designs.
Companies like Facebook, Twitter and LinkedIn, among many others, still create their
Android icons as boxes with rounded corners like iOS, so it is ultimately up to you to
decide if you want to follow the guidelines. Once suggestion I could give you is to not let
your icon design be an afterthought. Treat it with importance and youll see how the icon
by itself will give your app an added level of professionalism.
For a good reference about icon creation, you could watch the video called Lets talk
icons located at http://vimeo.com/90938384
Another important thing to keep in mind is that, due to the diversity of device sizes and
screen densities, youll have to create icons and splash screens for all of the possible
devices, and for both portrait and landscape orientation. Your app icons and splash screens
live in /app/assets/iphone and /app/assets/android, as seen in Figure 7.17.

Figure 7.17:
Default icons and splash screens for iOS and Android
To create your app icons and splash screens, simply open each of this files, replace the
contents with your own images, and save with the same name in the same location. Its a
time consuming process but will ensure that your images are appropriate for each device.
Luckily, and again thanks to the active developer community, theres a tool called TiCons
(Titanium Icons) that can do all the hard work for you. TiCons comes in two flavors:
Command-Line interface or Website. Ill show you how to use the website to generate all
the images you need for your app.
To begin, youll only need to create 3 files.
The first file will be used as a base for all your iOS icons and should be a 1024x1024
pixels png.
The second one will be used as the base for your Android icons and should be a 512x512
pixels transparent png.
Finally, and arguably the most important one, is the base file for all you different splash
screens. This file should be a 2208x2208 pixels png, but the content itself should be kept
in the inner 1000x1000 box, allowing enough slack around for cutting landscape and
portrait images.
Once you have these images, head over to the TiCons website at http: //ticons.fokkezb.nl/
and select these 3 images in their appropriate locations, as seen in Figure 7.18.

Figure 7.18: TiCons


website main screen
Leave all the rest with the default values and click Generate. TiCons will take your 3
images, will crunch and resize, and will return a Zip file. Download this Zip file and open
it. Figure 7.19 illustrates the contents of this file.

Figure 7.19: All the images TiCons generated for you


As you can see, TiCons has created for you all the splash screens and app icons you need,
saving you hours of graphic design work. Whats left to do is to move the /app/android
and /app/iphone folders to the corresponding folder in your app. The platform folder is
an additional set of files with representations of your Android app icons for multiple
screen densities. Move these as well to your /platform/android/res, being careful not to
delete any custom theme youve created. Once this is done, your PhotoMEME app is
complete, with its app icon, splash screen and cross-platform functionality.

7.4 Summary
In this chapter we built the last app of the book. We learned a couple interesting things
here.
Taking Pictures
We saw how to take pictures using Titanium.Media.showCamera(). We also saw how
there are certain Android devices that could return pictures with incorrect orientation
information, and others that return images in extremely high resolution. For these two
cases we used a third-party module, which we wrapped in a CommonJS class for easy
implementation.
Custom fonts and transparent view backgrounds
We also learned how to use custom fonts, apply transparent backgrounds, add them to

images taken with the camera and merging all the objects together and create a single
image out of them. We saw how to use CommonJS to normalize platform-specific
function calls, making your code much more readable and easier to maintain.
Sharing images with social networks
We then explored the specifics of sharing text and images with social networks. We saw
Android Intents and how they are provided by the operating system, and used a third-party
module to access a similar functionality on iOS. To provide more consistency in the code,
we accessed these two features by using a single function call exposed by another module.
Creating Splash Screens and App Icons
Last but not least, we saw the diversity of images that need to be created for app icons and
splash screens in order to account for all the different device sizes and screen densities,
and used the TiCons online tool so save us hours of graphic design work.
This concludes the code for the book. However, Ill still want to share some thoughts with
you. In Chapter 8 Ill give you my Top 10 Tips for Successful Cross-platform
development. Ive used these tips in national and international speaking engagements and
for this book Im making them available as a highresolution Infographic, which you could
print and have it always handy.

Chapter 8

Top 10 Tips for successful cross-platform


development
In this chapter I share with you my Top 10 Tips for Successful Cross-Platform
Development with Appcelerator. The list is in many ways a collection of the most
important things weve seen throughout the book; a cheat sheet if you like.
The chapter is going to be short, but packed with good information. Im sure that if you
keeping these tips handy, theyll help you stay focused in building best-in-class native
apps.

8.1 Beauty is relative to the platform


Take a look at Figure 8.1, which shows the Evernote mobile app running on iOS 8,
Android 4.4.4 and Windows Phone 8.1.
These screenshots were taken at the same time, and are showing the main screen of the
app, logged in as the same user, so the data is exactly the same. However, the user
interface is completely different across platforms; still they are beautiful.

Figure 8.1: Evernote for iOS, Android and Windows Phone


The concept of a beautiful Android app is very different to a beautiful iOS app. Take a
step back, learn how the platform works and implement your branding around it. Always
remember that even if your app renders differently across platforms, with Appcelerator
youll still be able to use a single code-base and have a very high percentage of code

reusability.

8.2 Code reuse is for your apps logic, not necessarily for UI
code
There are many misconceptions about code reuse with Appcelerator, or any cross-platform
tool for that matter. Expecting 100% code reuse not only represents little control over your
apps UI/UX, but also most likely means that your app will look exactly the same across
all target platforms. Some people think this is the ultimate goal of a cross-platform tool,
but thats wrong: thats the goal of a web browser. Reusability however is achievable with
your apps logic, as we saw particularly in Chapter 7, were we created CommonJS
modules for the Edit Dialog and Social Sharing. These modules acted as normalizers for
platform-specific functions, thus increasing the percentage or reused code. 8.3. Always
think web service
I admit its not easy: it took me a while, as a former web developer, to recognize and
accept this, but take it from me, its worth the effort, and youre apps will be better and
better. To help you even more in your journey, I created an app template you can use every
time you create a new app, seen in Figure 8.2.

Figure 8.2: Crossplatform App Template


This template provides the Alloy cross-platform architecture needed to maintain platformspecific user interfaces, with content and logic reusability. You can download the app
template from https://github.com/ricardoalcocer/ AlloyAppTemplate.

8.3 Always think web service


In chapter 6 we did some Twitter integration using the Codebird library, which in turn
gives us access to the Twitter API. We dont know in which programming language

Twitter writes its software, what type of database server theyre using or the structure in
which theyre storing their data. In fact, the only thing we know is what they want us to
know, what is given to us through the Twitter API. The Twitter API is a set of abstract web
services that were designed to provide access to the internals of Twitter, regardless of how
youre going to use the data, and even when this sounds limiting, you can in fact build a
full Twitter client using only their web services.
Since were developing cross-platform apps, I recommend you build your code
completely abstract, just as if it was a web service: a local web service if you like. Then on
top of this, build the native user interfaces, which are consumers of our local web
services. Using this architecture you can make sure that all the user interface code is
completely decoupled from the logic, and both can flow independently. Whats more, it
really will not make that much of a difference if youre using a TabbedBar on iOS and a
ViewPager on Android (like we did in Chapter 4), because after all, the user interface code
is simply a consumer of your application logic.

8.4 Tabs : Deep vs. Shallow


iOS tabs have a built-in NavigationController which allows you to have multiple levels of
navigation inside each tab. Android Tabs however are shallow, and should have no in-tab
navigation. To illustrate this, Ill show you how the Facebook app for Android is doing it
wrong. Figure 8.3 shows the Notifications Tab of the Facebook app for Android.

Figure 8.3: Facebook notifications


window 8.5. Know your target platforms Read the User Interface Guidelines
As per Android design guidelines, tapping on the back button in the main screen with tabs
should kill the app. Now, if you click on any of the notifications on the Facebook app,
youll see whats illustrated in Figure 8.4.

Figure 8.4: In-tab


navigation on the Facebook app
Facebook tries to implement an iOS-like functionality that provides in-tab navigation.
There are two problems with this. First, youre in the Notifications tab but the ActionBar
title says Comments. This is confusing and counterintuitive. Second and most important is
that the back button now is re-defined, and instead of closing the app, it takes you back to
the previous screen.
As a rule of thumb, dont try to force navigation inside your Android tabs. Doing it will
break the operation of the back button and will make your app feel awkward. For more
information about this concept, refer to the Android Design Guidelines at
http://developer.android.com/design/ patterns/app-structure.html.

8.5 Know your target platforms Read the User Interface


Guidelines
The best way of knowing whats available to your app and what you should and should
not do, is by reading each platforms user interface guidelines. Unless you own and use on
a daily basis the operating systems youre targeting, and feel like you thoroughly know
their behavioral and visual similarities and differences, I suggest you take time to read
them in full. Find iOS guidelines at https://developer.apple.com/library/ios/documentation/
userexperience/conceptual/mobilehig/ and Androids at http://developer.

android.com/design/index.html.
After reading through these documents, youll have a wealth of information that will help
you to understand each platform, design better user interfaces and know what to look for
in the Titanium API, or alternatively as a third-party module.

8.6 Work with your design team


If youre a graphic artist, make sure you learn about each platform, their navigation
paradigms and their visual language. As we saw in the Conference app in chapter 4, there
are subtle differences that make a great difference in usability.
If youre a programmer and theres a graphic artist in your team, or youre working as a
contractor/freelancer for an agency that is giving you mock-ups of the app to be built,
learn to work with them and educate them. Help them to understand that each platform has
a native way of displaying information, laying out screens and implementing navigation,
and these differences go far beyond Android having a back button and an ActionBar.
Mobile platforms are different, so in principle your cross-platform apps will look slightly
different across platforms.

8.7 Dont fear modules


The goal of Appcelerator has never been to expose 100% of each native SDK supported,
but rather, to provide a comprehensive top-level cross-platform API. To cover the features
not officially exposed, it offers a Native Module Development Framework, which
Objective-C and Java developers can use to expose additional features and functionality.
Weve used some of these modules throughout the book and youve seen how they
dramatically enhance the overall quality and user experience. Learn to find modules, use
them and embrace them.
8.8. Love your target platforms

8.8 Love your target platforms


Dont let your personal preference influence the design, functionality and quality of your
cross-platform apps. If you love iOS, thats no reason to show more commitment to your
iOS app, leaving behind your Android users. Learn to love each platform with their
strengths and limitations. Learn to compare them, but not criticize them. They are all good
in their own right and in their own contexts. Always try to build the best possible app for
the platform youre targeting.

8.9 Test often


Since your app by definition will have both cross-platform and platform-specific code and
components, make sure you test often. Dont spend days working on the Android version,

to then run it on iOS and realize the object positions are off, fonts need adjusting, or your
app is simply crashing on load. My recommendation is to test often, so if something
breaks on one platform, you can immediately know whats the problem related to.

8.10 Be your user


Your user is the most important part of your app. Always be a user of the target platform,
know how the platform works, then use your app and be your user. Look around, examine
other apps, compare, analyze. When youre testing your own app ask yourself: Would I
use this app? Does this app feels right? Make sure it conforms to your own quality
standards. If you love your app, most likely your users will love it too.

8.11 Summary
These are my Top 10 Tips for Cross-platform mobile development using Appcelerator.
Ive made these tips available as an Infographic, seen in Figure 8.5.

Figure 8.5:
Infographic
Im making this Infographic available to readers of this book as a hi-resolution JPEG from
this link: http://bit.ly/tialloyinfographiclg. The image was 8.11. Summary
designed in poster size, so feel free to print it out if youd like - Im sure Ill look
awesome on your wall.

Appendix A

Working with JavaScript


This chapter covers:
JavaScript basic syntax
Working with JavaScript Functions
Working with JavaScript Arrays
Working with JavaScript Objects
Understanding JSON
In this chapter I offer you a JavaScript refresher, a cheat sheet of sorts. This is by no
means a full guide of the JavaScript language, but rather a summary of the most important
aspects, and those that are relevant to your Titanium coding. Use this chapter as a
reference while reading the rest of the book or while reading Titanium code written by
other developers.
JavaScript is very simple to learn, but make no mistake; JavaScript is a very powerful
language. It may have started on the browser, but with the creation of Node.js, its now
also used as a server-side language, and its considered the future of enterprise. JavaScript
may well become the single most important computer language youll learn.

A.1 Basic syntax A.1.1 Case Sensitivity


JavaScript is case sensitive. This means that the method toString needs to be written with
a lowercase t and a capital S. The same thing holds true for your own code, functions and
variables.

A.1.2 Comments
You can write comment lines using double slashes // and comment blocks using /* and */.
See below.
// this is a commment
/* this is
also a comment */

A.1.3 Variables and variable scope


In JavaScript you can create a variable on the fly by just creating it and using it. However
it is recommended that you properly declare variables using the var keyword. By doing
this youre explicitly telling JavaScript that youre using that portion of memory to store a
value, and when youre no longer using it, JavaScript will automatically release it from

memory. To assign a value to a variable you use a single equal (=) sign.
Variable scope, or where you can access variables from is a bit tricky in JavaScript so Ill
explain using some examples.
var a =1;
function one () {
alert (a);
}
one () ;

The result of running this script is a message box with the number 1, proving that variable
a is global and accessible from inside the function even when it was created outside of it.
var a =1;
function two (a){
alert (a);
}
two (100) ;

In this case, when we call function two it will display the number 100 because its
displaying the value of the variable a that is local to the function. They both can be named
a and wont conflict with one another because they belong to different scopes.
var a =1;
function three () {
var a = 3;
alert (a);
}
three () ;

This case is exactly the same one as before, but no value was sent to the function, resulting
in displaying the number 3.
function saySomething () {
var message = This JavaScript thing is cool ;
alert ( The message is : + message ) ;
}
saySomething () ;
alert ( The message is : + message ) ;

Finally in this example well get en error when trying to display the variable message from
outside the function, as this variable belongs to the function and is not accessible to
anyone outside its local scope.

A.1.4 Data Types


JavaScript has only 7 data types. Any other type of data you need for your program youll
have to create yourself using user-defined objects.
String
var greeting = Hello ;
var greeting = Hello ;

Number
var price =100;

Boolean
var completed = false ;

Array
var colors =[ Red , White , Green ]; var values =[100 ,200 ,300];

Object
var employee ={
name : Steve ,
department : Engineering
}

Null
An actual value that means empty
Undefined
The value of a variable that has no value

A.1.5 Conditional and Conjuction operations


When building conditional statements in JavaScript, you can use any of the following
eight comparison operators and related conjunction operators.
Conditional Operators Equal to (==)
// for x =2

Exactly equal to, value and datatype (===)

x == 10 // returns false x == 2 // returns true


// for x =2

Not Equal (!=)

x ===2 // returns true x === 2 // returns false


// for x =2

Not Equal, value and datatype (!==)

x != 10 // returns true
// for x =2

Greater than (>)

x !== 2 // returns true x !== 2 // returns false


// for x =2

Less than (<)

x > 10 // returns false


// for x =2

Greater than and equal to (>=)


// for x =2 x >= 10 // returns false Less than and equal to (<=)
x < 10 // returns true

\ for x =2
x <= 10 // returns true

Conjunction Operators AND operator (&&)


// x is less than 5 AND y equals 3

OR operator (||)

(x < 5 && y ==3)


// x is less than 5 OR y equals 3
(x < 5 || y ==3)

There are three ways of building conditional (if-then-else) blocks.


Traditional IF-THEN-ELSE block
if(x===2) //true condition else //false condition
TERNARY
(x ===2) ? ( true condition ) : Using && AND || operators
( false condition )
(x ===2) && ( true condition ) || ( false condition )

A.2 Functions
Functions are a very important part of JavaScript. With a JavaScript function you can
accomplish from basic things like adding two numbers, to creating a complete class that
provides you access to the Twitter API.

A.2.1 Basic function


A basic function in JavaScript starts with the function keyword, the name of the function
and its arguments, if any, separated by commas and wrapped in parenthesis. The contents
of the function are wrapped in curly brackets. A.2. Functions
function add ( num1 , num2 ){ var result =0;
result = num1 + num2 ; return result ;
}

To call this function, you use the following syntax.


var firstNumber =5;
var secondNumber =5;
var total = sum ( firstNumber , secondNumber );

At this point variable total has the result of the function, that is, the number 10.

A.2.2 Assigning functions to variables


Functions in JavaScript can also be assigned to a variable, which comes in handy when
you want to pass functions to other parts of your programs.
var sum = function ( num1 , num2 ){
var result =0;
result = num1 + num2 ;
return result ;
}
var total = sum (5 ,3) ;

A.2.3 Self-invoking functions


In JavaScript you can create anonymous or self-invoking functions. The main purpose of
this special type of function is to be able to keep its functionality and memory usage inside
its own variable scope. These functions are executed immediately.
( function () {
// perform
// your operations
// here
}() );

If your self-invoking function needs to receive arguments, youll format it like this.
function ( arg1 , arg2 ){
// perform
// your operations
// here
}( val1 , val2 )

Any variables inside this function belong to the function, and are not available to the rest
of your program.

A.3 Arrays

JavaScript arrays can be created using the Array keyword.


var colors = new Array () ; colors [0]= Red ;
colors [1]= White ;
colors [2]= Green ;

The above example is the traditional way of building arrays in JavaScript. However the
recommended way is using Array Literals.
var colors =[ Red , White , Green ];

A.4 Objects
In JavaScript youre always working with Objects. When you create a variable of type
String, it is actually an object of type String, which automatically inherits a set of
properties and methods.
var carmake = Honda ;
alert ( carmake . toUpperCase () ) ;

toUpperCase is a method inside the String object that will automatically convert your
String to upper case.
You can create your own objects using the object literal syntax.
var person ={
name : jack ,
email : jack@ctu . com ,
twitter : @jackb_ctu
};
alert ( person . name );

A.5. Combining Arrays and Object Literals

A.5 Combining Arrays and Object Literals


JavaScript offers a lot of flexibility when it comes to building complex objects. You can
combine Arrays and Objects to achieve interesting things. The following example is an
Array with two Objects as elements.
var arr =[
{ key1 : Cat } ,
{ key2 : Dog }
];
alert ( arr [0]. key1 );

You could also store an Array as an object property.


var obj ={
key :[
Cat ,
Dog
]
};
alert ( obj . key [1]) ;

Arrays can also be properties of Objects stored in Arrays.


var arr =[
{
key :[
Cat , Dog
]
}

];
alert ( arr [0]. key [1]) ;

You can even store Functions as object properties. var arr =[


{
key : function () { alert ( Cat ) ; }
}
];
arr [0]. key () ;

A.6 Using functions to create objects


JavaScript has a concept called closures. Closures are a special type of function where its
local scope of variables is kept alive even when the function has returned, as opposed to
previous examples that once the function returns you no longer have access its state.
Consider the following example.
var customObj = function () {
var myCount =0;
return {
addOne : function () {
myCount ++;
},
getTotal : function () {
return myCount ;
}
};
}() ;
customObj . addOne () ;
customObj . addOne () ;
customObj . addOne () ;
alert ( customObj . getTotal () );

Notice in this previous example that when you run the function, what youre actually
doing is building an object with two methods: addOne and getTotal. These two methods
are accessing the value of the myCount variable, which is local to the main function, and
even after the function returns, you not only can get the value of the variable by calling
getTotal, but you can also change its value by calling addOne. This pattern is called the
Yahoo Module Pattern. JavaScript closures can be difficult to understand at first, but use
them and theyll become second nature.

A.7 JSON
JSON stands for JavaScript Object Notation and its a text-based data interchange open
standard based on JavaScript objects and arrays. JSON is sometimes considered a light
weight version of XML, in the sense that it serves the same data interchange purpose, but
its smaller in size. JSON is an ideal format to send data from and to mobile devices
because the data packets are often small (as compared to XML), thus in the end protecting
the users data plan.
A.7. JSON
Today theres a JSON implementation for virtually any programming language, so if your
App reads JSON, it will be capable of interchanging data with almost any web service.
The format of a JSON string is very similar to Arrays and Object literals. Consider the

following example.
[ { id : 1,
name : Apple ,
url : http :// apple . com , tags : [ iphone , ipad ]
},
{
id : 2,
name : Android ,
url : http :// android . com , tags : [ googletv , chromecast ]
}
]

Notice that at plain sight it looks exactly the same as an Array literal with two object
literals as elements. The main difference is that the properties are strings (notice the
double quotes in the property names. This is a JSON requirement and they have to be
double quotation marks. Other than that, its like working with JavaScript objects.

A.7.1 From JSON to native object


You will usually receive a JSON string from a web service, such as Twitter, Facebook, or
even your own, and well see more about this later. When you receive your JSON you
could easily convert it into a native JavaScript object like so:
var myJSON = [{ id :1 , name : Apple , url : http :// apple . com , tags : [ iphone , ipad ]} ,{ id :2 , name : Android , url :
http :// android . com , tags : [ googletv , chromecast ] }] ;
var JSONObj = JSON . parse ( myJSON );
alert ( JSONObj [1]. name );

A.8 From native object to JSON


If your app is generating data to be sent to a web service, you could turn any native
JavaScript object into its JSON representation. Following up on the previous example: var
backTOJSON=JSON.stringify(JSONObj);
The stringify method takes any JavaScript object (Array literal, Object literal, combination
of both) and will turn it into a string representation fully compliant with the JSON format.
The real beauty and power of JSON comes from the fact that it is available across different
languages and platforms. Each JSON implementation has a version of JSON.parse and
JSON.stringify, and the former converts the string into a native object of the platform in in
which it is running, making JSON a truly platform agnostic data interchange format.

A.9 Summary
In this appendix, you saw
The importance of understanding the JavaScript language
Different ways of building functions
Using array and object literals
Using functions to return objects
How JSON works and its importance in mobile applications

Some online references for additional learning:


http://www.w3schools.com/js/default.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript
http://json.org

Appendix B

Installing and configuring Appcelerator


Installing Titanium is not difficult; in fact, for the most part everything is installed
automatically. However, there are some instances when the installation fails. Most of the
times the problem is not Titanium itself, but its dependencies.
In this appendix Ill guide you through the process of installing Titanium using its default
installation process, and also explain all its dependencies and how to troubleshoot
common installation and configuration problems.
Note
The following steps refer to Titanium Studio version 3.3.0. Steps and screen shots may be
different for other versions.

B.1 Titanium and its dependencies


When youre troubleshooting installation problems, youll run into four different
components, all with their own version numbers. Its important to understand the whole
dependency chain and how the work. Not only itll help you in understanding possible
installation and configuration errors, but also youll understand their flexibility and their
potential for automation of processes and/or integration with other tools. Im detailing
these components for the purpose of explaining the components and dependencies, but
keep in mind that all of them are installed for you when you install and configure Titanium
Studio.

B.1.1 Main components


Titanium CLI
Titanium itself is a command-line tool written in Node.JS (JavaScript), and available as a
package downloadable from NPM (Node Package Manager). This is the main component,
which you can use straight from the Terminal/CommandWindow, or from Titanium
Studio.
Alloy CLI
The Alloy CLI is also a Node.js package available from NPM, which is maintained as an
independent project. Alloy by itself doesnt do much, since it is a Titanium pre-compiler.
You could use Titanium without Alloy, but not Alloy without Titanium.
Titanium SDK
The Titanium SDK is used by Titanium in order to provide the high-level cross-platform
API used by Titanium. The Titanium CLI compiles against this Titanium SDK and there

could be features of the Titanium CLI only available starting on specific versions of the
Titanium SDK.
Titanium Studio
Titanium Studio is Appcelerators IDE (Integrated development environment). Titanium
Studio uses the Titanium CLI, the Alloy CLI and the Titanium SDKs, plus provides
additional features like syntax highlighting, debugging capabilities, SDK management and
project management, among many others.

B.1.2 Obtaining Xcode and iOS SDK


To obtain Xcode and the iOS SDK, register for a free Apple account at https:
//developer.apple.com/register/. Then, navigate to https://developer.
apple.com/xcode/downloads/ and download the current version of Xcode and the current
iOS SDK. With this free developer account youll be able to test in the iOS Simulator.
If you wish to test on device or deploy to the Apple App Store, youll need to enroll in the
iPhone Developer Program at https://developer.apple. com/programs/start/standard/
For additional details about installing and configuring Xcode refer to https:
//wiki.appcelerator.org/display/guides2/Installing+the+iOS+SDK B.1. Titanium and its
dependencies

B.1.3 Obtaining the Android SDK


The Android SDK Manager can be obtained from http://developer.android. com/sdk. The
SDK Manager can be freely downloaded and youre not required to register at this point.
The package youre downloading requires no installation; simply decompress it and store
it somewhere in your hard drive.
What youve downloaded at this point is the SDK Manger and a host of other tools
required for compiling Android apps. You can access the manger by running the android
program located inside the tools folder, and from this manager you download the
necessary SDKs.
The Android tools require the Java Development Kit (JDK), which comes pre-installed in
Mac computers. For Windows and Linux it needs to be manually installed and configured
in a specific way in order for Titanium to find it. For more details about this refer to
https://wiki.appcelerator.org/display/ guides2/Installing+Oracle+JDK. Make sure you
follow the steps exactly as they are laid out.
For additional details about installing and configuring the Android SDKs refer to
https://wiki.appcelerator.org/display/guides2/Installing+the+ Android+SDK

B.1.4 Titanium CLI


The Titanium CLI provides all the tools needed for building and deploying Titanium apps.

It can be used on its own if youd rather not use Titanium Studio. From the Titanium CLI
you can also examine your complete Titanium installation and has configuration tools that
can help you figure out configuration problems and conflicts. For a full syntax reference
refer to http://docs.appcelerator.com/titanium/3.0/#!/guide/Titanium_ CommandLine_Interface_Reference

B.1.5 Node.js
Node.js is a tool designed for taking JavaScript out of the browser and bringing it to the
server. The Titanium CLI and Alloy are written in Node.js and for that reason it is
required. If at some point you run into problems that appear to be related to the Node.js
installation, refer to the guide located at
https://wiki.appcelerator.org/display/guides2/Installing+Node

B.1.6 Git
Git is a tool for managing collaborative development. Youve perhaps heard of Github, but
the two are different. Git is used to manage you software off-line, while Github is a place
you can use to store your Git-managed projects on the web. For information about
installing Git refer to https://wiki. appcelerator.org/display/guides2/Installing+Git

B.1.7 Genymotion
Genymotion is a set of Android emulators based on virtualized Android machines hosted
on VirtualBox. As of Titanium 3.2 Genymotion is supported from the Titanium CLI, and
as of 3.3 officially supported by Titanium Studio. Genymotion can be obtained from
http://www.genymotion.com/, is free for personal used and requires a subscription for any
other use. For additional installation details refer to
http://docs.appcelerator.com/titanium/3.0/ #!/guide/Installing_Genymotion

B.2 Titanium Studio


Titanium Studio is an Eclipse-based text editor that provides an Integrated Development
Environment (IDE) for all you Titanium needs, from creating a new project, to publishing
to the App Store and Google Play market. Titanium Studio is cross-platform and available
for Windows, Mac and Linux (Ubuntu) computers.
Note
Titanium Studio always requires an active Internet connection

B.2.1 Installing Titanium Studio

To begin, point your browser to http://www.appcelerator.com/developers/. From there,


select the option to download Titanium Studio. It it may require you to create a free
Titanium account.
Once the download completes, install it and run it, and youll be greeted with the screen
shown in Figure B.1.

Figure B.1: First


screen after installing Titanium Studio
If youve already created a Titanium account, go ahead and login here. If you dont have
an account, youll be able to create one from this screen. Immediately after you login,
Titanium Studio will ask you to specify a location for your Workspace, shown in Figure
B.2.

Figure B.2: Select Studio Workspace


A Workspace is simply a directory on your computer where all your Titanium projects will
be stored. If youve worked with Eclipse before, then youre familiar with this screen. If
you check Use this as the default and do not ask again, this location will be saved. You
can always switch or create new workspaces by selecting File >Switch Workspaces in
Titanium Studio.
Once Studio launches for the first time it will check if there are any updates available, as

seen in Figure B.3 If this is your first run, I suggest you install every update available. In
the future however, if youre prompted to install updates, I suggest you carefully read
what is being updated and decide whether or not you need the update at this point.
Installing updates without paying attention to whats actually being updated may result in
breaking existing apps.

Figure B.3: Update


Titanium Studio components

B.2.2 Configuring
Studio will now launch the Platform Configuration dialog, shown in Figure B.4, which
will guide you in the process of installing the SDKs for the platforms you wish to develop
for.

Figure B.4: Platform Configuration screen


If for any reason you dont see this dialog, you can always access from the Studio
Dashboard, as shown in Figure B.5.

Figure B.5: How to


re-launch the Dashboard and Platform Configuration window
The Platform Configuration window is used to automatically download and configure the
native platform SDKs. Depending on the speed of your Internet connection, the process of
downloading and configuring the platform SDKs make take from 30 minutes to over an
hour. This is because for iOS development, it is required to download Xcode, with itself is
over 1 gigabytes.

Figure B.6:
Android configuration
On the Android side, first the Android SDK Manger is downloaded and the each
individual SDK version you selected, as seen on Figure B.6. You dont need to download
all Android versions, only the ones you want to develop and test for. If youre not sure,
download the most recent one. You can always come back to the screen and download
additional ones.
After everything has been downloaded and configured, youll see that Titanium Studio
will show a green checkmark next to the SDKs that have been properly installed and
configured, as you can see in Figure B.7.

Figure B.7: Android configuration


If at any point you need to make changes to the SDKs that have already been installed and
configured, you can go the preferences screen and look under Studio >Platforms, and then
the platform you want to work with, as seen in Figure B.8.

Figure B.8: SDK Preferences


After following these steps, youre ready to use Titanium Studio. This process is fully
automated. In some occasions, you may run into some problems when working on
Windows and Linux. Mac OSX is very strict as far as software locations are concerned,
which makes it easier to configure. Windows and Linux on the other hand are more
flexible for the developer and the user, and this flexibility makes the process of creating
automated installers more uncertain, as the installer wont necessarily know where to look
for software installations.

Appendix C

Submitting apps to Google Play and


iTunes
Now that you know how to build cross-platform mobile apps using Appcelerator, the next
step is to submit your apps to the official application markets. In this appendix Ill guide
you through the steps you need to take to submit your apps to Google Play and iTunes,
and as example, Ill be showing the steps I followed to submit the PhotoMEME app from
Chapter 7.
One important thing to keep in mind is that Appcelerator, as a native framework, will
generate for you the binary apps in the format required by the application markets. Studio
will provide you with screens to facilitate the process, but once the apps have been built
and signed, the rest of the steps are the same as for any other native developer,
Appcelerator or not.
The steps outlined here have remained essentially the same for some years, however, they
could change without much notice. To keep yourself up-todate on the app submission
process, please the official guide for Android at
https://wiki.appcelerator.org/display/guides2/Distributing+Android+apps and for iOS at
https://wiki.appcelerator.org/display/guides2/Distributing+iOS+apps .

C.1 Before you start


Before you start the process of compiling and signing your apps for submission, make sure
youve created an Apple iOS Developer account and a Google Android developer account.
The Apple account can be created at http://developer. apple.com and will cost $99 per
year. The Google account can be created from http://developer.google.com and will cost
you a one-time fee of $25.

C.2 Google Play


Before you can upload your app to Google Play, youll need to create a Key Pair
Certificate. This certificate will be used to sign your app, making sure that only you can
submit updates for it. Also keep in mind that youll have to create one certificate for each
app, and store them in a safe place, as youll need it every time you want submit an
update.
Keys are created using the keytool program thats included with your Java installation.
To create your key go to your terminal / Command Window and type:

keytool - genkeypair friendly_name >


-v - keystore < file / path / name > - alias <
- keyalg RSA - sigalg SHA1withRSA - validity 10000

File/path/name is the name of the file that will be created. The alias is a friendly name for
this file. If your app is called invoices, you could us the alias invoiceskey. Once you
hit enter youll be prompted with some information about you, which will be used to
create the digital signature. Youll then be prompted for a password and the file will be
created.
To verify that the file was properly created and has the right data, you could use the
following command.
keytool - list -v - keystore < file / path / name >

After creating your Key, youre ready to compile and sign your app with it. Open up
Studio with your project and from the toolbar select Package from the Run drop down
menu, as seen in Figure C.1.

C.2.1 Building and signing your app


From Studio, select Package from the Run dropdown menu (Figure C.1).

Figure C.1: Package application


This will populate the next box with new options, from which you should select Android
App Store (Figure C.2).

Figure C.2: Platforms to package for


After selecting this, a Wizard will pop up requesting details about this distribution, shown
in Figure C.3.

Figure C.3: Select Android


SDK
The first item to select is the SDK to compile the app with. If youre unsure, select the
version you were using during the development phase.

Figure C.4: Add key to


sign with
Figure C.4 shows the rest of items to provide. The green checkmark will appear with the
data appears to be correct. When finished click on Publish and youll have a signed
APK in the specified location. Youre now ready to prepare your Google Play Store entry.

C.2.2 Preparing your Google Play entry and submitting the


app
Having your APK properly signed, youre ready to go to the Developer Console at
http://developer.android.com/distribute. Login with your Android Developer email and
password and youll be taken to the dashboard shown in Figure C.5.

Figure C.5:
Android Developer Console
Click on Publish an Android App on Google Play and youll be prompted for the
information in Figure C.6.

Figure C.6: Add


APK
You upload your APK here or start preparing your listing even if the app is not yet
finished. In any case, the next step is to prepare the listing, which you can see in Figure
C.7.
Fill out all the required information for your app. In this page you submit all your app
images, select supported languages and set your app price, among other details. After
youve filled out all the information, youre ready to publish.

Figure C.7: Ready


to publish
Figure C.8 shows the drop down from which youll select to publish your app.

Figure C.8: Published app


The Google Play Store is not curated, which means that after you publish, theres no
human being reading your listing or testing your app. After about an hour you can go to
the Google Play store and search for your app, which will be displayed as seen in Figure
C.9.

Figure C.9: Published app


Success! Publishing apps for Android is pretty straightforward. Now lets look at the
process for the iTunes App Store.

C.3 iTunes App Store


The process of submitting iOS apps is a little different, with some additional steps to be
taken. The first thing you need to do is create your distribution certificate and provisioning
profiles. These steps are not Appceleratorspecific, however the official Appcelerator
documentation offers a guide on how to set this up at
http://docs.appcelerator.com/titanium/3.0/#!/guide/ Deploying_to_iOS_devices-section27595262_DeployingtoiOSdevices-Apple% 27sDeveloperprogram.

C.3.1 Preparing the app listing


For iTunes its best if you first create the app entry, so point your browser to
https://itunesconnect.apple.com, shown in Figure C.10.

Figure C.10: iTunes


Connect Home
From the iTunes Connect main screen select My Apps and from the following screen
select the + sign to add a new app.
The following screen is where the data you entered in Appcelerator and the Developer
Portal come together. Every time you create an Appcelerator App, you have to add an app
id. This app id is part of your Distribution Certificate, which is now shown in Figure C.11
under Bundle ID.

Figure C.11: Add


app meta data
If you put together your Bundle ID and your Bundle ID Suffix, you get the app id you
entered when you created your app in the first place. This is important because that app id
is carried over inside your app and if it doesnt match with this screen, the submission will
fail.

Figure C.12: Fill out details for your app


Next fill out all the details of your app (Figure C.12). Youll be asked to upload
screenshots for different screen sizes. Make sure you follow the size guidelines and that
your images have no transparency or alpha channels. Once your listing is ready, you can
now move to the next step, which is building and signing your app.

C.3.2 Building and singing your app


Go to Studio, select your app, select Package and this time choose iOS iTunes Store as
seen in Figure C.13.

Figure C.13: Distribute for iOS iTunes Store


A wizard will pop up, similar to the one for Android, shown in Figure C.14. The
information on this screen refers to distribution certificates and provisioning profiles I
mentioned before, so if you have everything in place this screens will come pre-filled. If
not, the wizard will guide you through the process of getting the system ready.

Figure C.14: iTunes


Distribution Wizard
When you complete the wizard your app will be built and sent over to Xcode. Studio will
automatically open Xcode for you, so from the Window menu select Organizer, from
which youll verify and upload your app.

C.3.3 Verifying and submitting your app


The Xcode Organizer will show the app you just compiled, as seen in Figure C.15.

Figure C.15: Xcode


Organizer
Click on the Validate button, and Xcode will run a process to validate the integrity of this
build, seen in Figure C.16.

Figure C.16:
Validate your app
This is the process that any native iOS developer needs to go through. Some versions of
Appcelerator have shown a warning message after clicking Validate. If you get a warning,
try unchecking the checkbox on the bottom of this screen.
After successfully validating the app youre ready to submit.
Figure C.17 above shows the submission process, which could take a couple minutes
depending on the size of your app and the speed of your Internet connection. Youre now
ready to add this build to your listing.

Figure C.17: Submit your app to iTunes Connect

C.3.4 Adding your app to the listing and publishing

Go back to iTunes Connect and select your apps listing. Scroll down and select the + sign
next to Build. This will show a popup (Figure C.18) with the file you just submitted
through XCode. Select the build and click Done.

Figure C.18: Add


this build to the app listing
Your finally ready to submit! In the top-right corner youll see Submit for Review button
shown in Figure C.19.

Figure C.19: Submit app for review


After clicking this button, your app will change status, as seen in Figure C.20.

Figure C.20: Waiting for review


At this point youll also receive an email confirming that the app has been submitted for
review. Its never clear how long itll take for the app to be reviewed, but I think that 7
days is a reasonable estimate. In case of rejection, Apple will provide a reason for
rejection. To avoid surprises, make sure you abide by the App Store Review Guidelines at
https://developer.apple.com/ app-store/review/guidelines/.

List of Figures
1.1 How the Appcelerator SDK works 6
1.2 Comparison of Classic and Alloy . 9
1.3 Native representation of the Switch control . 9
1.4 Native Switch running on iOS and Android . . 11
1.5 New Project Configuration . 12
1.6 Project Explorer . 12
1.7 Running your app 13
2.1 Relationship between the platform SDKs, the Titanium API and Alloy 16
2.2 How the Titanium API is organized . . 18
2.3 Non-MVC Titanium Code . . 19
2.4 Tight coupling in Titanium Classic 20
2.5 Alloy MVC . . 21
2.6 Titanium Classic and Alloy side-by-side 24
2.7 Anatomy of the XML tag . . 24
2.8 Comparing TSS to CSS 26
2.9 The Alloy dollar sign symbol 28
2.10 Alloy normalizes API calls . . 30
2.11 How our MP3 will look on iOS and Android . 32
2.12 Differences between the iOS Title Bar and Androids ActionBar . 32
2.13 Creating a new mobile project . . 34
2.14 Importing projects into Studio . . 35
2.15 MP3 Player Skeleton . . 37
2.16 Strategy for building the buttons strip . 39
2.17 Main buttons container 40
2.18 Views to hold each button image . 40
2.19 Adding images to buttons 41
2.20 Our current assets and styles folders . . 50 2.21 Add theme folder(s)
51 2.22 Add assets and styles to your theme(s)
. 52 2.23 Alloys position in the Titanium development cycle 53 2.24 MP3
Player with new theme applied . . 56 2.25 Adding additional theme
57 2.26 Change backgroundImage in content class 57
2.27 Change color and position of the controlsbar class 58
3.1 Create a new Alloy Widget . 62
3.2 Enter Widget name . . 63
3.3 Widget folder structure 65
3.4 Widget.xml and Widget.tss side-by-side 66
3.5 Location of widget local assets and styles as compared with global ones
. . 67
3.6 Testing your basic/default widget in iOS and Android . 69
3.7 Widget detached from host app 71
3.8 Create new Alloy Widget . . 72

3.9 Code to move from index.xml to the widget.xml . 73


3.10 Transferring view code from app to Widget . 73
3.11 Identifying classes and ids . . 74
3.12 Transferring style code from app to Widget . 75
3.13 Methods that belong to the Widget . . 76
3.14 Folder structure with Widget themes . . 82
4.1 Alloy Conference app running on iOS 7 and Android 4.4 88
4.2 The Schedule Tab 90
4.3 The Venue Tab 91
4.4 The Conversation Tab . 92
4.5 The Videos Tab . . 93
4.6 Project Template window . . 94
4.7 Basic representations of tabs on iOS and Android . 96
4.8 Create new controller . 97
4.9 Add controller name . . 97
4.10 Project explorer with all controllers created . 98
4.11 Structure of internationalization folder . 100
4.12 Relationship between index.xml, index.tss and language file . . 101
4.13 iOS tabs compared to Android tabs . . 102
4.14 Tab Icon sizes 102
4.15 iOS Image Locations . . 105 4.16 Android Image Locations
. . 105 4.17 ActionBar Title . . 107 4.18
Configure ActionBar Style . . 109 4.19 Download resources
. . 110 4.20 The /platform/android folder . 111
4.21 Comparison of default and custom Android theme 112 4.22 ActionBar
divider line . 112 4.23 ActionBar divider line
. 113
5.1 Platform-specific code is not re-usable, but the data and logic is. . 117
5.2 How the ViewPager works . . 118
5.3 Module folder structure 119
5.4 Platform folders inside Views . 121
5.5 Loading controllers into your code 123
5.6 The ViewPager successfully added to schedule.xml 125
5.7 Recap of our goal: Two platform-specific containers with common content
126
5.8 TabbedBar and ScrollableView on iOS . 127
5.9 App on iOS . 130
5.10 The TableView 131
5.11 TableView and TableViewRow . . 132
5.12 Layout of the TableViewRow 133
5.13 TableView on iOS and Android . . 135
5.14 JSON Editor On-Line . 137
5.15 Location of data files . . 138
5.16 Move TableViewRow to dayrow.xml . . 139
5.17 Creating controllers dynamically . 140

5.18 Populating data in views . 141


5.19 Create SQLite Database 142
5.20 Convert JSON to CSV . 143
5.21 Import CSV to SQLite . 144
5.22 Confirm Table Schema . 144
5.23 SQLite Data Browser . 145
5.24 Create model 147
5.25 Create model schema . . 148
5.26 TalkDetails Screen . 151
5.27 Event object 154
5.28 iOS Navigation Controller . . 156
5.29 Events conflict . . 158
6.1 Venue Window . . 162
6.2 Conversation Window showing latest tweets . 165
6.3 How ListView templates relate to the screen layout 166
6.4 Create a new Twitter App . . 168
6.5 Add your apps meta-data . . 168
6.6 Grab API Key and API Secret . . 169
6.7 JSON response displayed in the console 173
6.8 Looping though Twitter results . . 173
6.9 Relationship of transformed object and ListView markup . . 176
6.10 Missing refresh button on Android 177
6.11 Android refresh button on ActionBar . . 180
6.12 Expected results for Video Window 182
6.13 How to get videos from YouTube feed . 187
6.14 Relationship for transformed object and ListView markup . . 188
7.1 Wireframe representation of our app . . 195
7.2 Main screen . 196
7.3 Photo taken and ready for editing 197
7.4 Enter text . . 198
7.5 Generating Meme 199
7.6 Sharing Meme with Social Networks . . 200
7.7 Main Screen . . 201
7.8 Help dialog . 204
7.9 How components are laid out on the screen . 207
7.10 The photo has been taken . . 208
7.11 Custom fonts 210
7.12 Editable areas and dialog boxes 211
7.13 Sharing dialog on Android . . 215
7.14 Platform-specific progress indicators . . 218
7.15 Cross-platform sharing . 219
7.16 App icons on iOS and Android . . 220
7.17 Default icons and splash screens for iOS and Android . . 221
7.18 TiCons website main screen . 222
7.19 All the images TiCons generated for you 223

8.1 Evernote for iOS, Android and Windows Phone . . 226 8.2 Cross-platform
App Template 227 8.3 Facebook notifications window
. . 228 8.4 In-tab navigation on the Facebook app . 229 8.5
Infographic . 232
B.1 First screen after installing Titanium Studio . . 251
B.2 Select Studio Workspace . 251
B.3 Update Titanium Studio components . . 252
B.4 Platform Configuration screen 253
B.5 How to re-launch the Dashboard and Platform Configuration window253
B.6 Android configuration . 254
B.7 Android configuration . 255
B.8 SDK Preferences . 255
C.1 Package application . . 259
C.2 Platforms to package for 259
C.3 Select Android SDK . . 260
C.4 Add key to sign with . . 260
C.5 Android Developer Console . . 261
C.6 Add APK . . 262
C.7 Ready to publish . 263
C.8 Published app 263
C.9 Published app 264
C.10 iTunes Connect Home . 265
C.11 Add app meta data 265
C.12 Fill out details for your app . 266
C.13 Distribute for iOS iTunes Store . . 267
C.14 iTunes Distribution Wizard . 267
C.15 Xcode Organizer . 268
C.16 Validate your app 268
C.17 Submit your app to iTunes Connect . . 269
C.18 Add this build to the app listing . 269
C.19 Submit app for review . 270
C.20 Waiting for review 270

List of Tables
1.1 Native Platform Tools . 7
2.1 Alloy MVC Components 22
2.2 User interface Components required for the MP3 Player 36
2.3 Properties for the main window . . 43
3.1 Contents of the Widget.json file . . 64
6.1 Properties in the args variable 171 7.1 HEX Opacity Values
. . 209

Index
9-patch, 113
absolute path, 75
ActionBar, 33, 38, 46, 49, 102, 167 ActionBar Style, 108, 200
ActionBar Style Generator, 200 ActionBar Styles, 38
actionbar.icon, 107
ActionBarExtras, 116
advanced Android customization, 87 AlertDialog, 213
ALLOY, 8
Alloy, 3, 711, 1317, 2025, 60 Alloy CLI, 63
alloy generate controller, 98
Alloy Models, 116
Alloy View, 24
Alloy.CFG, 55, 122
Alloy.createController, 122
Alloy.createModel, 150
Alloy.Globals, 122
alloy.js, 122
Alpha channel, 209
Android, 35, 13, 116
Android Activity, 178
Android Intents, 215
Android Manifest, 111
Android themes, 87, 108
API, 4, 116
API Keys, 162
App Store, 5, 203
App URL Schemes, 180 app.tss, 59, 133
Appcelerator, 38, 1015, 21 Appcelerators, 4
AppCompat, 109
Apple, 5
Apple App Store, 194
ARGB, 194, 209
args variable, 141
avatar, 93
Backbone, 90, 116, 147 backward compatibility, 109 best practices, 4
Blackberry 10, 4
bridge, 78
canOpenURL, 164
chain, 123
Classic, 3, 811, 15, 16, 19, 20, 23,

30, 31, 60
Clean, 101
CLI, 11, 63, 127
Codebird library, 227
codebird.js, 167
com.companyname.widgetid, 63 comma-separated values, 143 Command Window, 63
CommonJS, 78, 138, 194
config.json, 55, 58, 67, 72, 163 console.log, 154
controller, 61
ConvertCSV, 143
createAlertDialog, 212
cross-platform, 35, 33, 49, 135 CSS, 4, 8, 11, 1517, 22, 40 CSV, 143
custom font, 210
FlexSpace, 38
framework, 4, 5, 8, 15, 16, 19, 60 frameworks, 5, 21
getString, 100
Github, 70, 119 Gitt.io, 70
global settings, 122 global styles, 133 Google Maps, 91 Google Play, 5, 194 grid, 61
grid format, 61
Dark, 39
dark theme, 38
data access, 135 data models, 116 data-binding, 166 databases, 115
debug, 121
decoupled, 122, 228 dependency, 62, 72 detach, 81
Div, 39
DOM, 26
DrawerLayout, 116
Eclipse, 11
Emulating, 91
emulators, 11
encrypted, 147
English, 92
event listeners, 127
exports, 78
extra-extra high-resolution, 103
Facebook, 92, 115, 194 factory methods, 25 Firefox, 142
hardcoded, 132
hashtag, 92, 168
HEX, 209
HEX triplets, 210
HTML, 4, 11, 13, 1517, 20, 22, 24,
39, 40
HTTP, 162
hybrid, 5

i18n, 99, 122, 124


icon, 194, 220
IDE, 10
ImageView, 40, 61
in-tab navigation, 228
index.tss, 74, 75
index.xml, 69
internationalization, 99 invalidateOptionsMenu, 178 iOS, 35, 13, 116
iPad, 4
iPhone, 35
ISO 639-1, 100
iTunes, 5
Java, 35, 14, 89, 116 JavaScript, 35, 8, 10, 11, 1315, 17,
24
JS, 21
JSON, 41, 93, 135
JSON parsing, 89
JSON.parse, 149
jsoneditoronline.org, 136, 173 JSSQL, 145
L, 101
Label, 25
landscape, 220
language files, 92
Light, 39
light theme, 38
LightDarkBar, 39
ListView, 130, 161, 181 ListViews, 89
LiveView, 13
Logical Density Factor, 103 look-and-feel, 14
navigation paradigms, 230 non-retina, 102
normalizers, 226
Objective-C, 35, 14, 89, 116 onCreateOptionsMenu, 178 onScroll, 128
onTouchEnd, 40, 47, 74 onTouchStart, 40, 47, 74 opacity, 48
Open Source, 11
orientation, 220
Persistent App Properties, 116 phones, 4
platform-specific, 120, 158 platform-specific folders, 89 Play Store, 203
portrait, 220
Project Explorer, 62
project wizard, 62
maintainability, 61
maintainable, 89
map function, 174

marketplace, 119
mdpi, 103
meta-data, 65
mobile strategy, 5
MobileWeb, 4
Models, 135, 147
modules, 116
multi-language support, 87
MVC, 8, 10, 15, 16, 1922, 29, 49,
59, 60
namespace, 1719, 25, 100
native module, 120
Navigation Controller, 155
README.md, 68
refresh, 13
Require tag, 98
res-hdpi, 103
res-ldpi, 103
res-mdpi, 103
res-xhdpi, 103
res-xxhpi, 103
retina, 102
reusability, 68, 118 reusable component, 76 reusable package, 71 reuse, 123
reverse URI format, 63 rotateAndResize, 205
ScrollableView, 127, 128, 163 scrolling list, 115
ScrollView, 131, 156
SDK, 35, 11, 14
Securely, 147
security, 147
Segmented Control, 90, 127, 128 separator, 134
setTimeout, 218
shallow, 155, 228
Share Intent, 194, 215
Sharing Intent, 216
showCamera, 205
simulator, 13
slide-in animation, 156
social networks, 194
Spanish, 92
Splash screen, 220
splash screens, 194
SQL Statements, 152
SQL Strings, 152
SQLite, 89, 135, 142
SQLite Databases, 116

SQLite Manager, 142


strings.xml, 100
Studio, 1012, 127
stylesheet, 101
stylesheets, 4, 1315, 17, 20
Supported Platforms, 4
supporting multiple Android screen
sizes and densities, 104
tab architecture, 87
Tab Bar, 102
TabbedBar, 90, 127, 228 TabGroup, 94, 101, 121, 123 tablets, 4
TableView, 89, 115, 130, 135 TableViewRow, 131
Tabs, 87
template, 166
Terminal, 63, 98, 101
test often, 96
theme, 82
Themes, 49, 50, 54
themes, 4952, 55
third-party native modules, 88
ti clean, 101
Ti.App.Properties.removeProperty, 136 Ti.App.Properties.setObject method,
150
Ti.Locale, 100
Ti.UI, 25
Ti.UI.createButton, 18, 25
Ti.UI.createWindow, 25
Ti.UI.View, 24
tiapp.xml, 38, 39, 110, 119
TiCons, 221
Tint Color, 102
TiPebble, 116
TiSocial.Framework, 194, 216
Titanium, 8, 1520, 2226, 30, 31,
33, 34, 37, 39, 46, 49, 53,
55, 60
Titanium.Android.Menu, 178
Titanium.Media.showCamera(), 194 TitaniumControls.com, 70
toImage, 198, 218
Toolbar, 33, 46, 49
TSS, 8, 15, 21, 23, 24, 40, 41
tweet, 93
Twitter, 92, 115, 161, 167, 194
Twitter API Keys, 168

UI, 14, 16, 17, 20, 22, 24, 33, 36, 39, 49
UI/UX, 4, 14, 90, 116
UIActivityViewController, 216
underscore.js, 174
usability, 118
user behavior, 118
user interface, 1417, 20, 24, 61, 92
versioning, 68
View, 22, 24
ViewPager, 90, 116, 118, 228 Views, 23
visual language, 230
web apps, 147
web browser, 162
Web Development, 14 web development, 15 web server, 162
Web Services, 162 Web services, 89
Widget, 61, 216
Widget names, 63 widget.js, 67
widget.json, 63, 68 widget.tss, 75
Window, 20, 23, 123 Windows Phone, 4 WPATH, 75
XML, 8, 15, 21, 2325 xxhdpi, 103
YouTube, 93, 161, 183

Вам также может понравиться