Archive for May, 2010

Building an Advanced Transaction UI with Titanium

Monday, May 31st, 2010

Building advanced user interfaces in Titanium is pretty easy – once you get the hang of it. In this tutorial, I’m going to walk through how to build an advanced transactional UI – one that might be used for example in an application that captures credit card and needs a signature right on the device. Square is currently a popular company located here in San Francisco that’s doing this type of app. We used their signature screen as an inspiration for this tutorial.

First, here’s what the screen will look like:

So, let’s first start off with with I call the wrapper view. The wrapper view is the main white box that serves as the main interface area. It has a shadow on the left and right and a drop shadow at the bottom. The main parts of this wrapper view are that it contains the signature, signature line, amount, etc. We start off by creating a basic window and view for the wrapper and the shadow.

var win = Ti.UI.createWindow({  
    backgroundColor:'#ddd'
});
 
// create our wrapper view.  we offset from the top -2px so that we can eliminate
// the top border from display
var wrapper = Ti.UI.createView({
	width:'95%',
	top:-2,
	height:250,
	borderColor:'#aaa',
	borderWidth:2,
	backgroundColor:'#fff'
});
 
// we create a simple view that serves as the bottom shadow of the wrapper view
var wrapperShadow = Ti.UI.createView({
	width:'95%',
	height:2,
	backgroundColor:'#bbb',
	top:247
});
 
win.add(wrapper);
win.add(wrapperShadow);

So, far, we’re just using simple views with some custom properties. Notice, we create the shadow by simply placing the view just below the wrapper and set the height to 2px but make him the same width as the wrapper and with a slightly lighter grey. This will create the shadow effect.

We also create a border with the wrapper view, but we offset his top position from -2 pixels from the parent, which effectively hides the top shadow. This gives a nice effect. Also notice that the wrapper is using a calculated percentage for the width, 95%.

Next, we want to add the buttons along the bottom. I’m using 2 simple pill like images and a fixed close image. The pill images will automatically stretch in Titanium. For the close button image, it’s a fixed size.

Now, add the buttons and customize them:

var doneButton = Ti.UI.createButton({
	backgroundImage:'blue.png',
	title:'Done',
	width:90,
	height:35,
	right:12,
	bottom:10,
	font:{fontFamily:'Arial',fontWeight:'bold',fontSize:14},
	opacity:0
});
 
var clearButton = Ti.UI.createButton({
	backgroundImage:'clear.png',
	width:26,
	height:27,
	right:20,
	top:10
});
 
win.add(doneButton);
win.add(clearButton);
 
var cancelButton = Ti.UI.createButton({
	backgroundImage:'gray.png',
	title:'Cancel',
	width:90,
	height:35,
	left:12,
	bottom:10,
	font:{fontFamily:'Arial',fontWeight:'bold',fontSize:14},
});
 
win.add(cancelButton);

Notice in my Done button, I make the initial opacity to 0 – effectively hiding it. I do this until the user signs which I’ll explain below.

Now, we’re going to add some text along the bottom for the Terms and Conditions.

var terms = Ti.UI.createLabel({
	text:'I agree that this demo is very very cool.\nCan we get a shout out?',
	textAlign:'center',
	width:'auto',
	height:'auto',
	font:{fontFamily:'Arial',fontSize:12},
	color:'#555',
	shadowColor:"#fff",
	shadowOffset:{x:1,y:1},
	bottom:12
});
 
win.add(terms);

Notice, we use a slight text shadow on the label.

Now, let’s start the middle wrapper area by drawing the signature line.

// our signature line is simply a 2px view
var sigLine = Ti.UI.createView({
	width:'90%',
	height:2,
	backgroundColor:'#aaa',
	bottom:40
});

A line can simply be created by creating a view at a fixed height (or width if vertical) and a backgroundColor to fill the space. In this case, we simply create a line that’s 90% of the parent container (the wrapper view).

Now, the name below the signature:

var sigName = Ti.UI.createLabel({
	text:'Jeff Haynie',
	textAlign:'center',
	width:'auto',
	height:'auto',
	font:{fontFamily:'Arial',fontWeight:'bold',fontSize:18},
	color:'#999',
	bottom:10
});

Simple enough.

Let’s now add the X next to the signature line, indicating the user should sign on the line.

var thex = Ti.UI.createLabel({
	text:'X',
	textAlign:'center',
	width:'auto',
	height:'auto',
	font:{fontFamily:'Arial',fontSize:24},
	color:'#aaa',
	bottom:45,
	left:20
});

We simply position the X text next to the left of the line.

Let’s add the price and the pay to description up near the top:

var price = Ti.UI.createLabel({
	text:'$9.99',
	width:'auto',
	height:'auto',
	left:25,
	top:8,
	color:'#333',
	font:{fontFamily:'Arial',fontSize:54},
	shadowColor:"#eee",
	shadowOffset:{x:1,y:1}
});
win.add(price);
 
var payto = Ti.UI.createLabel({
	text:'Pay to: Appcelerator, Inc.',
	width:'auto',
	height:'auto',
	left:28,
	top:70,
	color:'#777',
	font:{fontFamily:'Arial',fontSize:12},
	shadowColor:"#eee",
	shadowOffset:{x:0,y:1}
});
win.add(payto);
wrapper.add(sigLine);
wrapper.add(sigName);
wrapper.add(thex);

The next part is a custom module that I’ve developed using the Module SDK. More details on how to build modules can be found in the Module SDK documentation. We’ll have some specific module tutorials soon. Additionally, we’re going to be launching a Module marketplace really soon, so stay tuned.

Back to my signature, I created a simple module called Paint. It also you to create a simple paint view for simple drawing. Let’s add my custom module code:

var paint = Ti.Paint.createView({
	strokeWidth: 6,
	strokeColor:'#2a81df',
	zIndex:10,
	bottom:0,
	top:30
});
wrapper.add(paint);

The paint view allows me to customize the size of the pen and it’s color. I also place the paint view at zIndex 10 – simply above any of the other views. That way if the user draws over the signature line or any of the others elements, it will be drawn above them.

Now, we can add some simple logic to the application.

clearButton.addEventListener('click',function()
{
	// clear the canvas
	paint.clear();
	doneButton.animate({opacity:0,duration:500});
});

In my new module, I exposed a method to clear the view of the drawing. So, I simply attach a click listener to my button, clear the paint view and hide the Done button with a nice animation.

Now, let’s show the Done button when the user is done signing – or at least after they start the signature. I simply do this once the touchend event is fired on the view – meaning the user at least starting painting and finished.

paint.addEventListener('touchend',function()
{
	doneButton.animate({opacity:1,duration:500});
});

We simply just fade in the Done button with a nice animation on the opacity.

Our done button simply just prints an alert. Trivial:

doneButton.addEventListener('click',function()
{
	alert("Thanks!");
});

Now, let’s open up the window and force our orientation on the window.

win.orientationModes = [ 
	Titanium.UI.LANDSCAPE_RIGHT
];
win.open();
 
Titanium.UI.orientation = Titanium.UI.LANDSCAPE_RIGHT;

The first line will tell the window which orientations that the window can be rotated to. The last line simply forces the UI device orientation into a specific mode, programmatically. Since we can’t force the user to rotate the device, we can software rotate it for them.

And, that’s about it. Now, for a little video demonstration of the full application put together.

This tutorial demonstrates how you can build fairly advanced user interfaces without much code. It also shows the power of the use of Titanium views to do a lot of graphical work for you. You can always use images for your drawing, but something it’s much easier and faster to simply use customized views.

How to create a Tweetie-like pull to refresh table

Monday, May 31st, 2010

We’ve had very many requests to add the ability to build Tweetie-like pull to refresh TableView functionality. This UI metaphor seems to have become very popular with many popular applications starting to adopt this design.

Starting in the upcoming 1.4 release, you’ll be able to do this. In this tutorial, I’m going to explain how to support this in your own application.

First, let’s create a simple tableview and a base window. I’m assuming you’re putting this in your app.js directly.

var win = Ti.UI.createWindow();
win.open();
 
var data = [
	{title:"Row 1"},
	{title:"Row 2"},
	{title:"Row 3"}
];
var tableView = Ti.UI.createTableView({
	data: data
});

Now, we’re going to create the header pull view. This view will be displayed when you go “above” the top of the table view.

We’re going to create a view with a nice blue background and a bottom border. Notice how I create a single line border at the bottom.

var border = Ti.UI.createView({
	backgroundColor:"#576c89",
	height:2,
	bottom:0
})
 
var tableHeader = Ti.UI.createView({
	backgroundColor:"#e2e7ed",
	width:320,
	height:60
});
 
// fake it til ya make it..  create a 2 pixel
// bottom border
tableHeader.add(border);

Now, we’re going to add the elements inside the header view for controlling the arrow and the labels.

 
var arrow = Ti.UI.createView({
	backgroundImage:"../images/whiteArrow.png",
	width:23,
	height:60,
	bottom:10,
	left:20
});
 
var statusLabel = Ti.UI.createLabel({
	text:"Pull to reload",
	left:55,
	width:200,
	bottom:30,
	height:"auto",
	color:"#576c89",
	textAlign:"center",
	font:{fontSize:13,fontWeight:"bold"},
	shadowColor:"#999",
	shadowOffset:{x:0,y:1}
});
 
var lastUpdatedLabel = Ti.UI.createLabel({
	text:"Last Updated: "+formatDate(),
	left:55,
	width:200,
	bottom:15,
	height:"auto",
	color:"#576c89",
	textAlign:"center",
	font:{fontSize:12},
	shadowColor:"#999",
	shadowOffset:{x:0,y:1}
});
var actInd = Titanium.UI.createActivityIndicator({
	left:20,
	bottom:13,
	width:30,
	height:30
});

Notice we’re using a date utility function for formatting. You can paste this code to handle the formatting now:

function formatDate()
{
	var d = new Date;
	var datestr = d.getMonth()+'/'+d.getDate()+'/'+d.getFullYear();
	if (date.getHours()>=12)
	{
           datestr+=' '+(d.getHours()==12 ? 
              d.getHours() : d.getHours()-12)+':'+
              d.getMinutes()+' PM';
	}
	else
	{
		datestr+=' '+date.getHours()+':'+date.getMinutes()+' AM';
	}
	return datestr;
}

Now, the important part. We need to assign our header view to the tableview using the property headerPullView.

tableView.headerPullView = tableHeader;

This will tell the table view to use that special view when scrolling above the top of the table.

The next step is to handle our events to do the pull logic. Instead of building all this logic inside Titanium, we wanted to expose the lower-level events to you so you can build upon these capabilities to make more interesting applications from it.

There’s 2 new events: scroll and scrollEnd. You’ll receive the scroll event each time the user scrolls up and down. The scrollEnd event will be fired once scrolling stops.

Let’s add the code to handle the scrolling to determine when to show the message:

tableView.addEventListener('scroll',function(e)
{
	var offset = e.contentOffset.y;
	if (offset <= -65.0 && !pulling)
	{
		var t = Ti.UI.create2DMatrix();
		t = t.rotate(-180);
		pulling = true;
		arrow.animate({transform:t,duration:180});
		statusLabel.text = "Release to refresh...";
	}
	else if (pulling && offset > -65.0 && offset < 0)
	{
		pulling = false;
		var t = Ti.UI.create2DMatrix();
		arrow.animate({transform:t,duration:180});
		statusLabel.text = "Pull down to refresh...";
	}
});
tableView.addEventListener('scrollEnd',function(e)
{
	if (pulling && !reloading && e.contentOffset.y <= -65.0)
	{
		reloading = true;
		pulling = false;
		arrow.hide();
		actInd.show();
		statusLabel.text = "Reloading...";
		tableView.setContentInsets({top:60},{animated:true});
		arrow.transform=Ti.UI.create2DMatrix();
		beginReloading();
	}
});

You’ll notice we’re calling the beginReloading. This function is where you’ll want to do your reload logic. In most cases, you’re going to use a web service call to fetch the data remotely.

In our example, we’re simply going to append new rows to the bottom. In a real application, you’re most likely going to call setData to reload the data (or if no changes, simply do nothing).

Also notice a fun method we’re using setContentInsets. This method will change the content position inset of the tableview. In this code, we’re simply lowering it by 60 pixels from the top. That ensures that 60 pixels of our header view remain visible while we’re reloading. In the endReloading will raise it with the following code tableView.setContentInsets({top:0},{animated:true});.

var pulling = false;
var reloading = false;
 
function beginReloading()
{
	// just mock out the reload
	setTimeout(endReloading,2000);
}
 
function endReloading()
{
	// simulate loading 
	for (var c=lastRow;c<lastRow+10;c++)
	{
		tableView.appendRow({title:"Row "+c});
	}
	lastRow += 10;
 
	// when you're done, just reset
	tableView.setContentInsets({top:0},{animated:true});
	reloading = false;
	lastUpdatedLabel.text = "Last Updated: "+formatDate();
	statusLabel.text = "Pull down to refresh...";
	actInd.hide();
	arrow.show();
}

We keep 2 state variables pulling and reloading that are used by the event handlers. The function beginReloading in our example simply sets a timer for 2 seconds to simulate a web service call. The endReloading code will then append some rows and then reset the header view and state.

So, one nice piece of code to point out is how to animate the arrow. We don’t need to use two arrows – we can simply use one arrow and animate it. In this case, we apply a simple rotation transform to rotate the arrow 180 degrees. To rotate it back, we can simply create an empty 2d matrix, called the identity matrix, and set it.

Now, a little video that demonstrates the entire demo. Note, this entire demo is now in Kitchen Sink under the Table Views section.

To view the full source of this tutorial, you can look at the Kitchen Sink version of the file here. Note: this code only works either on head or 1.4+.

Next tutorial, I’ll show you using the same event callbacks to create a continuously scrollable table view which can background fetch rows as you scroll towards the bottom.

Help us Save the Gulf (as featured on CNN TV)

Sunday, May 30th, 2010

This weekend CNN featured on TV the Oil Reporter application (see video below). Oil Reporter was built on Titanium by Appcelerator partner Intridea in partnership with the Crisis Commons.

How we’re doing our part

While this effort has much political and environmental debate, at Appcelerator we’re simply trying to help in our own little way. We’ve started by providing a great platform for quickly building applications like Oil Reporter. We’re working with Crisis Commons and other governmental/non-governmental organizations to organize technology volunteers and help match them with organizations needing assistance during the relief. We’ve been helping to provide a common data platform and API for use in this effort and in future disasters. We’re also donating not only our time and resources but 100% of the first month proceeds made through the Oil Reporter relief coupon for any developer that signs up for a Titanium Professional subscription by June 30th.

How you can help too!

There is much more to do to help the Gulf region, which is why we are reaching out to the community of more than 47,000 Titanium Developers to participate in several ways:


  • Attend the upcoming free Webcast on Tuesday, June 1st “How Intridea Built Oil Reporter and How You Can Extend Oil Tracker” to learn more about building mobile apps with Oil Reporter data.
  • Volunteer to Develop New Apps. Recruited developers will be matched with government agencies and animal rescue organizations for a coordinated effort to better identify hotspots for crisis mitigation and protection of the natural environment, wildlife, etc.
  • Get Oil Reporter and Tweet your support for the initiative. “RT @appcelerator Announcing OilReporter: How Developers Can Aid Gulf #OilSpill Recovery http://bit.ly/9WMoRa”. Live in the Gulf Region? Volunteer as a data collector through the Deepwater Horizon Unified Command.

Better Know A Titanium Developer: Chris Marin

Sunday, May 30th, 2010



Welcome to part one of our 47,725 part series, Better Know A Titanium Developer!  Our developer community comes from a wide variety of backgrounds and are working on some amazing projects – we thought it might be interesting to check in with some of them to share their story with the community.  Today, we shine the spotlight on Chris Marin of Computer Sciences Corporation.

Who are you and what would you say you “do”?


My name is Christopher Marin. I work for CSC, a large IT services company, as a Site Architect. I lead the technical, analytics and design teams for csc.com. I started out my career working for a startup that did web software for the first generation BlackBerries and Motorola PageWriters.

How did you discover Titanium, and what do you like about it?

I discovered Titanium in the summer of 2009 off a DZone link, soon after I got my first iPhone. A few years ago, my team rebuilt a legacy Java app with over 500,000 lines of code to Ruby on Rails. When we launched, we had less than 10,000 lines of code, despite the fact we had added substantial new functionality. The reason this was possible was because Rails allowed us to work at an appropriately high level of abstraction. That whole notion of silicon (computer chips) getting cheaper than carbon (humans) really appeals to me. That’s why the benefits of Titanium were so immediately apparent to me. Why should I write 50-2000 lines of Objective-C or Java code when I can do it in a single line of JavaScript? It seems so wasteful to work at anything other than the highest level of abstraction possible, assuming you can still meet your performance criteria.

The other thing that really appealed to me about Titanium, and again is in the same vein of avoiding unnecessary waste of valuable programmer time, is the ability to target multiple platforms with a single codebase. It doesn’t seem like any single mobile platform is going to dominate things the way we had in the previous desktop era. With that in mind, it becomes more and more necessary to target the top mobile platforms. Redoing work in low level languages, to target multiple platforms, just isn’t feasible for the majority of projects. Frameworks like Titanium however, make it a quite reasonable course of action.

How do you use Titanium today? What apps have you released using Titanium?

My group uses Titanium for the CSC Mobile application. Others groups at CSC are also using Titanium.

What is your favorite mobile app (written using any technology) and why?

When Steve Jobs made his assertion that the iPad would be a “magical device”, I was pretty skeptical. However, I must admit that the first time I played Für Elise on the Magic Piano by Smule, I was blown away. The ability to reinterpret something as venerable as playing Beethoven on a piano, and do it in such a way that a rank novice can participate in that type of experience, really inspires me. This field is still so young, just imagine what we’ll come up with in the next decade!

What is your favorite vintage video game (anything post SNES doesn’t count)?

One game I got really hooked on was Herzog Zwei for the Sega Genesis. It was one of the first Real Time Strategy games, and in my opinion is still one of the best ever made. In fact, I think it would make a great iPad app.

Community Q&A Improvements: Round 1

Friday, May 28th, 2010

Since launching the new developer.appcelerator.com, members of our community have shared quite a bit of feedback on the community Q&A section, which we still envision to be a great model for community members to help one another out with questions they might have. However, it was not without its shortcomings. We’ve heard your voices load and clear and today have rolled out the first in a series of improvements to community Q&A.

Search

We’ve integrated Google custom search to help index our existing Q&A content – we hope to continue to improve our search capabilities throughout the site, but we think this will have an immediate impact on the quality of search results on Q&A.

Comments

Ever asked a question, and the answer wasn’t an answer but a request for more clarifying information? Right, we thought so. Users now have the ability to add comments to questions and answers, so that clarifications and troubleshooting information can be gathered without registering junk answers.

FAQ

Now when a question gains enough notoriety, an Appcelerator crew member (holler at one here) can mark it as a frequently asked question. We’ll be adding questions to this list right away, as well as questions regarding known issues and the like.

Subscriptions

You can now manage your subscriptions in your “My Q&A” page in the main dev center nav (upper right, under the login link). You can subscribe/unsubscribe to tags to stay in the loop.

More To Come

We’re not done with Q&A or Dev Center – not by a longshot. We plan to add message boards to the mix for general discussion items, new ways for community members to add content, and new rewards for community members who help out their fellow developers. During this process, we’ll be listening to feedback from you – if you haven’t already, sound off on what you’d like to see next in the Appcelerator Developer Center. Thank you for being a Titanium Developer – you complete us!