Appcelerator extending UI elements

If you have every used <NavigationWindow> in your Alloy code you know that it will only work with iOS. But what if you don’t want to have to duplicate all your code for android?

// index.xml
<Alloy>
    <NavigationWindow id="win1" platform="ios">
        <Window class="container">
            <View>
                <Button onClick="showDetails">Show Details</Button>
            </View>
        </Window>
    </NavigationWindow>
    // Terrible we are duplicating code!!
    <Window class="container" platform="android">
        <View>
            <Button onClick="showDetails">Show Details</Button>
        </View>
    </Window>
</Alloy>

This is NOT GOOD!

So then why not use and Require tag? Ok thats not so bad, but then we have to create a new subView.xml file, subView.tss, and subView.js controller for it.

// index.xml
<Alloy>
    <Require platform="android" src="subView"/>
    <NavigationWindow id="win1" platform="ios">
        <Require src="subView"/>
    </NavigationWindow>
</Alloy>

// subView.xml
<Window class="container">
    <View>
        <Button onClick="showDetails">Show Details</Button>
    </View>
</Window>

This is BETTER but its still…

What about if we extended the NavigationWindow? Let see what that might look like.

// lib/ui.js
exports.createNavigationWindow = function(args) {
    /***
     * This will be used for the Android Window
     * @param {Object} args
     */
    function navigationWindow(args) {

        this.open = function(options) {
            args.window.open();
        };

        // Convert an iOS openWindow call to Window.open
        this.openWindow = function(win) {
            win.open();
        };

        // Convert an iOS closeWindow call to Window.close
        this.closeWindow = function(win) {
            win.close();
        };
    }

    // Android returns the above function
    if (OS_ANDROID) {
        return new navigationWindow(args);
    } else {
        return Ti.UI.iOS.createNavigationWindow(args);
    }
}; 

// views/index.xml
// Add the module="ui" to NavigationWindow
<Alloy>
    <NavigationWindow module="ui" id="win1">
        <Window class="container">
            <View>
                <Button onClick="showDetails">Show Details</Button>
            </View>
        </Window>
    </NavigationWindow>
</Alloy>

Ok now we’re talking, but what is this file doing? For starters we are exporting our own createNavigationWindow that our <NavigationWindow module="ui" id="win1"> tag will call first.

In this way we intercept the call to the built in Ti.UI.iOS.createNavigationWindow and determine who’s calling it and modify the return value. If its iOS we just return the original createNavigationWindow since that is what iOS can use.

If however, if it’s Android we will override the createNavigationWindow functions and divert them to the basic open or close functions of the Window class. This way when we call it we don’t need to use any sort of logic to determine which function to call.

So finally when we call the openWindow it works with both platforms.

function showDetails() {
    var win2 = Alloy.createController("details").getView();
    $.win1.openWindow(win2);
}
Loading Facebook Comments ...