In this blog we are going to create an animated "split apart view". The idea is much like when you tap on an application group on the iOS home screen and the screen appears to split apart revealing the apps in that group.

The implementation is quite simple. It should be clear that no view is actually going to split. The split effect can be achieved however as follows.
We will use two views, each with
their background image set with the image of the window to be split
apart - we shall call these the "doors" or leftView and rightView. We
will also need to have the view that will be behind the doors when they
open - insideView. The doors and insideView will be placed on top of the
window that we want to be split apart - hostWin - when it is time for
the effect. The impatient can skip straight to the example on github.
We are going to build a CommonJS module naming the file
SplitApartView.js. First we need to get the details of the device we are using:
height, width and half screen dimensions (which we will use later).
Also up front, we are going to define some common animation settings.
var screenHeight = Ti.Platform.displayCaps.platformHeight;
var screenWidth = Ti.Platform.displayCaps.platformWidth;
var half_screen = {
top : 0,
height : screenHeight,
width : screenWidth / 2
};
var common_animation = {
top : 0,
duration : 500
};
When instantiating the module we need create the leftView and
rightView and hold on to the hostWin and insideView. Note, in the
code below we added an event listener to both doors so that when they
are tapped, the doors slide back into place and then be removed, along with
the insideView, from the hostWin.
exports.SplitApartView = function(obj) {
this.hostWin = obj.hostWin;
this.insideView = obj.insideView;
this.animated = false;
this.leftView = Ti.UI.createView(mixin({
left : 0
}, half_screen));
this.rightView = Ti.UI.createView(mixin({
right : 0
}, half_screen));
var me = this;
function close() {
me.rightView.animate(mixin({
right : 0
}, common_animation));
me.leftView.animate(mixin({
left : 0
}, common_animation), function() {
me.animated = false;
//Cleanup
obj.hostWin.remove(me.insideView);
obj.hostWin.remove(me.rightView);
obj.hostWin.remove(me.leftView);
});
}
this.rightView.addEventListener('click', close);
this.leftView.addEventListener('click', close);
};
Since we have already mentioned the door closing animation, we will included the animation for when the doors open. Note that the doors do not open fully or slide off the screen, so that we can tap them to close again.
exports.SplitApartView.prototype.open = function() {
if(!this.animated) {
var win = this.hostWin;
this.animated = true;
win.add(this.insideView);
win.add(this.leftView);
win.add(this.rightView);
this.rightView.animate(mixin({
right : -(screenWidth / 3)
}, common_animation));
this.leftView.animate(mixin({
left : -(screenWidth / 3)
}, common_animation));
}
};
Up to this point we have the opening and closing animations. We also
need the code that takes an image of the hostWin, splits it and uses each
half as the background image of the doors. The code is as follows:
var cropping = {
y : 0,
height : screenHeight,
width : screenWidth / 2
};
exports.SplitApartView.prototype.prepare = function() {
var screenShot = this.hostWin.toImage();
this.leftView.backgroundImage = screenShot.imageAsCropped(mixin({
x : 0
}, cropping));
this.rightView.backgroundImage = screenShot.imageAsCropped(mixin({
x : screenWidth / 2
}, cropping));
};
The reason why this code has been placed in a separate function
instead of incorporating it in the open function is that when combined,
the user experience can be laggy. Depending on the application the
prepare function can be called early after graphical changes to the
hostWin or if no further UI changes are expected.
You might have noticed the use of the mixin function that I used to
cut down on lines of code. I first saw it used way back in the Tweetanium
app. The code is here if you need it:
var empty = {};
var mixin = function(target, source) {
var name, s, i;
for(name in source) {
s = source[name];
if(!( name in target) || (target[name] !== s && (!( name in empty) || empty[name] !== s))) {
target[name] = s;
}
}
return target;
};
Here is an example of a very basic app.js file that uses the module.
var SplitApartView = require('/SplitApartView').SplitApartView;
var win = Ti.UI.createWindow({
backgroundColor: '#2192E3',
fullscreen: true
});
var insideView = Ti.UI.createView({
backgroundColor: "#666"
});
var textArea = Titanium.UI.createTextArea( {
height: 100,
width: 200,
borderColor: "black",
borderRadius: 10,
font : {
fontSize : 20
}
});
win.add(textArea);
var split = new SplitApartView({
hostWin: win,
insideView: insideView
});
win.addEventListener("swipe", function () {
split.prepare();
split.open();
});
win.open();
The textArea is placed in the middle of the host window. Add quite a
bit of text, then swipe the window and it should appear that the window
and text area are torn apart. Here are some screen shots showing the before and after.

A few extra things to do to improve the experience and module:
insideView to make it appear behind the
split window, e.g. shadows, textures etc.That is my blog for today.