SlideShare a Scribd company logo
1 of 29
Download to read offline
ALLOY WIDGETS
Improving code re-use through a library of bespoke UI
                    components.




                     TiConf.eu
            Martin Hudson, Jonti Hudson
                   February 2013
WHAT IS A WIDGET?

A self-contained bespoke UI component that
holds all the logic associated with its use.
WHAT IS A WIDGET?

A self-contained bespoke UI component that
holds all the logic associated with its use.

•   Create a re-usable library across multiple
    projects
WHAT IS A WIDGET?

A self-contained bespoke UI component that
holds all the logic associated with its use.

•   Create a re-usable library across multiple
    projects

•   Create components that manage cross-
    platform differences (e.g. a table edit / delete
    component)
WHAT IS A WIDGET?

A self-contained bespoke UI component that
holds all the logic associated with its use.

•   Create a re-usable library across multiple
    projects

•   Create components that manage cross-
    platform differences (e.g. a table edit / delete
    component)

•   Improve readability of code
WHAT IS A WIDGET?

A self-contained bespoke UI component that
holds all the logic associated with its use.

•   Create a re-usable library across multiple
    projects

•   Create components that manage cross-
    platform differences (e.g. a table edit / delete
    component)

•   Improve readability of code

•   Improve reliability due to re-use of tested
    components.
WHAT IS A WIDGET?
App                         Widget




             Multiple widgets in the same window...
WHAT IS A WIDGET?
App                          Widget




             ... or multiple instances of the same
             widget
A CUSTOM TABLE VIEW WIDGET
An example of building a cross-platform widget that encapsulates common
functionality but utilises platform specific behaviour.
CREATING A WIDGET
To create a new widget, right click the project name in the Titanium Studio
project view... and select New → Alloy Widget.
CREATING A WIDGET
To create a new widget, right click the project name in the Titanium Studio
project view... and select New → Alloy Widget.




Use a “Reverse domain” naming convention to ensure widget names are not
replicated when you share widgets with others.
WIDGET FILE STRUCTURE
A widgets folder is created with Controllers, Styles and Views sub-directories.




Note the absence of Models – this is because the main app should handle
data storage
USING A WIDGET
In the main app, we will call the newly created widget using the “Require” tag.

          App – index.xml                                Widget – widget.xml

  <Alloy>                                            <Alloy>
  <Window class="container">                            <TableView id="table"></TableView>
   <Require type="widget"                            </Alloy>
    src="co.mobiledatasystems.customEditableTable"
  id="table1">
   </Require>
   <Button id="btnEdit" title="Allow Editing"
  onClick="btnEdit_click_Event">
   </Button>
  </Window>
  </Alloy>
USING A WIDGET
In the main app, we will call the newly created widget using the “Require” tag.

          App – index.xml                                Widget – widget.xml

  <Alloy>                                            <Alloy>
  <Window class="container">                            <TableView id="table"></TableView>
   <Require type="widget"                            </Alloy>
    src="co.mobiledatasystems.customEditableTable"
  id="table1">
   </Require>
   <Button id="btnEdit" title="Allow Editing"
  onClick="btnEdit_click_Event">
   </Button>
  </Window>
  </Alloy>




Note we specify that we want a widget and reference the name of our new
widget. Alloy knows where to find it.
USING A WIDGET
In the main app, we will call the newly created widget using the “Require” tag.

          App – index.xml                                Widget – widget.xml

  <Alloy>                                            <Alloy>
  <Window class="container">                            <TableView id="table"></TableView>
   <Require type="widget"                            </Alloy>
    src="co.mobiledatasystems.customEditableTable"
  id="table1">
   </Require>
   <Button id="btnEdit" title="Allow Editing"
  onClick="btnEdit_click_Event">
   </Button>
  </Window>
  </Alloy>




 In the widget, we specify the UI components we want to expose. In our
 case it is only a TableView.
STYLING
          App – index.tss                Widget – widget.tss

".container": {
   backgroundColor:"white"
},
"#table1": {
   left: '10dp',
   right: '10dp',
   top: '20dp',
   bottom:'80dp'
},
"#btnEdit": {
   bottom:'10dp',
   left:'20dp',
   right:'20dp',
   height:'45dp'
}




We have referenced our instance of the
widget “table1” in index.xml
STYLING
           App – index.tss                  Widget – widget.tss

 ".container": {
    backgroundColor:"white"
 },
 "#table1": {
    left: '10dp',
    right: '10dp',
    top: '40dp',
    bottom:'80dp'
 },
 "#btnEdit": {
    bottom:'10dp',
    left:'20dp',
    right:'20dp',
    height:'45dp'
 }




Note, where possible, do all the styling of
widget components in the main app. This
ensures maximum re-usability across projects.
CONTROLLERS - INITIALISE
           App – index.tss                   Widget – widget.js
                                      //copy the arguments passed in to the widget via.
 ".container": {                      the xml and tss parameters
    backgroundColor:"white"
 },                                   var _args = arguments[0] || {};
 "#table1": {                         var editable = null;
    left: '10dp',
    right: '10dp',                    if(OS_ANDROID){
    top: '40dp',                      editable = false;
    bottom:'80dp'                     };
 },
                                      //get each element set in the widget's xml or tss
 "#btnEdit": {
                                      parameters
    bottom:'10dp',
    left:'20dp',
                                      Ti.API.info(JSON.stringify(_args));
    right:'20dp',
    height:'45dp'                     //iterate round all the parameters we have passed
 }                                    in

                                      for (var key in _args) {
                                        if (_args.hasOwnProperty(key)) {

In the widget's controller we can     //checks key is a direct property of _args, not

access all the parameters passed in   somewhere down the object tree


using the arguments[] array.                if(OS_ANDROID){
                                        	     switch (key){
CONTROLLERS - INITIALISE
           App – index.tss                   Widget – widget.js
                                      //copy the arguments passed in to the widget via.
 ".container": {                      the xml and tss parameters
    backgroundColor:"white"
 },                                   var _args = arguments[0] || {};
 "#table1": {                         var editable = null;
    left: '10dp',
    right: '10dp',                    if(OS_ANDROID){
    top: '40dp',                      editable = false;
    bottom:'80dp'                     };
 },
                                      //get each element set in the widget's xml or tss
 "#btnEdit": {
                                      parameters
    bottom:'10dp',
    left:'20dp',
                                      Ti.API.info(JSON.stringify(_args));
    right:'20dp',
    height:'45dp'                     //iterate round all the parameters we have passed
 }                                    in

                                      for (var key in _args) {
                                        if (_args.hasOwnProperty(key)) {

In the widget's controller we can     //checks key is a direct property of _args, not

access all the parameters passed in   somewhere down the object tree


using the arguments[] array.                if(OS_ANDROID){
                                        	     switch (key){
CONTROLLERS - INITIALISE
           App – index.tss                     Widget – widget.js
                                         //iterate round all the parameters we have passed
 ".container": {
                                         in
    backgroundColor:"white"
 },
                                         for (var key in _args) {
 "#table1": {
                                           if (_args.hasOwnProperty(key)) {
    left: '10dp',
    right: '10dp',
                                         //checks key is a direct property of _args, not
    top: '40dp',
                                         somewhere down the object tree
    bottom:'80dp'
 },
                                               if(OS_ANDROID){
 "#btnEdit": {
                                            	    switch (key){
    bottom:'10dp',
                                            	  	     case 'editing':
    left:'20dp',
                                            	  	     	    editable = _args[key];
    right:'20dp',
                                            	  	     	    break;
    height:'45dp'
                                            	  	     case 'moving': break; //android
 }
                                         doesn't recognise this property
                                            	  	     default:

We can read each parameter passed in        	

                                            	
                                               	

                                                 }
                                                     	    $.table[key] = _args[key];


and process them appropriately. In our      	

                                            	
                                               } else {
                                               	     $.table[key] = _args[key];
example “editable” and “moving” are         	  };
                                            };
iOS specific. We will set a local         };

variable in the case of Android.
CONTROLLERS - INITIALISE
           App – index.tss                     Widget – widget.js
                                         //iterate round all the parameters we have passed
 ".container": {
                                         in
    backgroundColor:"white"
 },
                                         for (var key in _args) {
 "#table1": {
                                           if (_args.hasOwnProperty(key)) {
    left: '10dp',
    right: '10dp',
                                         //checks key is a direct property of _args, not
    top: '40dp',
                                         somewhere down the object tree
    bottom:'80dp'
 },
                                               if(OS_ANDROID){
 "#btnEdit": {
                                            	    switch (key){
    bottom:'10dp',
                                            	  	     case 'editing':
    left:'20dp',
                                            	  	     	    editable = _args[key];
    right:'20dp',
                                            	  	     	    break;
    height:'45dp'
                                            	  	     case 'moving': break; //android
 }
                                         doesn't recognise this property
                                            	  	     default:

We can read each parameter passed in        	

                                            	
                                               	

                                                 }
                                                     	    $.table[key] = _args[key];


and process them appropriately. In our      	

                                            	
                                               } else {
                                               	     $.table[key] = _args[key];
example “editable” and “moving” are         	  };
                                            };
iOS specific. We will set a local         };

variable in the case of Android.
CONTROLLERS – CALLING FUNCTIONS
           App – index.js                                Widget – widget.js
$.index.open();                                     //custom method we expose to set the table's
                                                    data
var editMode = false;                               exports.setData = function(rows /*Ti.UI.Row*/){
                                                       $.table.setData(rows);
//create some data to put in the table              };
var rows = [];
for(var i=0;i<10;i++){                              //custom method we expose to allow the table to
rows.push(Ti.UI.createTableViewRow({title:'Row      be editable
number ' + i}));                                    exports.editing = function(edit /*bool*/){
};                                                     if(OS_IOS){
$.table1.setData(rows); //call the "setData"              $.table.editing = edit; //allow row
method we created in the widget                     editing on iPhone & iPad
                                                       } else {
//toggle the "editable" mode of the table                 editable = edit;
function btnEdit_click_Event(){                        };
   if(editMode){                                    };
      $.btnEdit.title = "Allow Editing";
      editMode = false;
   } else {                                      Using the commonJS framework, we
      $.btnEdit.title = "Cancel Editing";
      editMode = true;                           can expose functions in the widget. In
   };
   $.table1.editing(editMode); //call the        our example we expose “setData” so
"editing" method we created in the widget
};
                                                 we can populate the table after the
                                                 widget has created it.
CONTROLLERS – CALLING FUNCTIONS
           App – index.js                                Widget – widget.js
$.index.open();                                     //custom method we expose to set the table's
                                                    data
var editMode = false;                               exports.setData = function(rows /*Ti.UI.Row*/){
                                                       $.table.setData(rows);
//create some data to put in the table              };
var rows = [];
for(var i=0;i<10;i++){                              //custom method we expose to allow the table to
rows.push(Ti.UI.createTableViewRow({title:'Row      be editable
number ' + i}));                                    exports.editing = function(edit /*bool*/){
};                                                     if(OS_IOS){
$.table1.setData(rows); //call the "setData"              $.table.editing = edit; //allow row
method we created in the widget                     editing on iPhone & iPad
                                                       } else {
//toggle the "editable" mode of the table                 editable = edit;
function btnEdit_click_Event(){                        };
   if(editMode){                                    };
      $.btnEdit.title = "Allow Editing";
      editMode = false;
   } else {                                      Using the commonJS framework, we
      $.btnEdit.title = "Cancel Editing";
      editMode = true;                           can expose functions in the widget. In
   };
   $.table1.editing(editMode); //call the        our example we expose “setData” so
"editing" method we created in the widget
};
                                                 we can populate the table after the
                                                 widget has created it.
CONTROLLERS – CALLING FUNCTIONS
           App – index.js                                Widget – widget.js
$.index.open();                                     //custom method we expose to set the table's
                                                    data
var editMode = false;                               exports.setData = function(rows /*Ti.UI.Row*/){
                                                       $.table.setData(rows);
//create some data to put in the table              };
var rows = [];
for(var i=0;i<10;i++){                              //custom method we expose to allow the table to
rows.push(Ti.UI.createTableViewRow({title:'Row      be editable
number ' + i}));                                    exports.editing = function(edit /*bool*/){
};                                                     if(OS_IOS){
$.table1.setData(rows); //call the "setData"              $.table.editing = edit; //allow row
method we created in the widget                     editing on iPhone & iPad
                                                       } else {
//toggle the "editable" mode of the table                 editable = edit;
function btnEdit_click_Event(){                        };
   if(editMode){                                    };
      $.btnEdit.title = "Allow Editing";
      editMode = false;
   } else {
      $.btnEdit.title = "Cancel Editing";
      editMode = true;                           Here, the main app is responding to a
   };
   $.table1.editing(editMode); //call the        button click event and changing the
"editing" method we created in the widget
};
                                                 editable state in the widget.
CONTROLLERS – CALLING FUNCTIONS
           App – index.js                                Widget – widget.js
$.index.open();                                     //custom method we expose to set the table's
                                                    data
var editMode = false;                               exports.setData = function(rows /*Ti.UI.Row*/){
                                                       $.table.setData(rows);
//create some data to put in the table              };
var rows = [];
for(var i=0;i<10;i++){                              //custom method we expose to allow the table to
rows.push(Ti.UI.createTableViewRow({title:'Row      be editable
number ' + i}));                                    exports.editing = function(edit /*bool*/){
};                                                     if(OS_IOS){
$.table1.setData(rows); //call the "setData"              $.table.editing = edit; //allow row
method we created in the widget                     editing on iPhone & iPad
                                                       } else {
//toggle the "editable" mode of the table                 editable = edit;
function btnEdit_click_Event(){                        };
   if(editMode){                                    };
      $.btnEdit.title = "Allow Editing";
      editMode = false;
   } else {
      $.btnEdit.title = "Cancel Editing";
      editMode = true;                           Here, the main app is responding to a
   };
   $.table1.editing(editMode); //call the        button click event and changing the
"editing" method we created in the widget
};
                                                 editable state in the widget.
CONTROLLERS – HANDLING EVENTS
             App – index.js                                 Widget – widget.js
  $.table1.addEventListener('delete', function(r){    //create a handlers object that will contain
  Ti.API.info('row deleted: ' + JSON.stringify(r));   references to functions
  var dialog = Ti.UI.createAlertDialog({              var handlers = {};
      message: r.row.title,
      title: 'Deleted'                                //assign some functions that do nothing.
    });                                               handlers.click = function(r){};
    dialog.show();                                    handlers.deleteRow = function(r){};
  });
                                                      //expose a function that can pass in a reference
                                                      to an external function and assign the reference
In the widget we create an                            to the appropriate handler.

“addEventListener” function that has                  exports.addEventListener = function(listenerName,
                                                      listenerFunction){
two parameters, the name of the event                    switch (listenerName){
                                                            case 'click' :
and a reference to the function it will                        handlers.click = listenerFunction;
                                                               break;
call in the main app.                                       case 'delete' :
                                                               handlers.deleteRow = listenerFunction;
                                                               break;

We assign the reference to a                          };
                                                         };


“handlers” object we created in the                   if(OS_IOS){
widget.                                                  $.table.addEventListener('delete',
                                                      function(r){
CONTROLLERS – HANDLING EVENTS
             App – index.js                                 Widget – widget.js
  $.table1.addEventListener('delete', function(r){    //create a handlers object that will contain
  Ti.API.info('row deleted: ' + JSON.stringify(r));   references to functions
  var dialog = Ti.UI.createAlertDialog({              var handlers = {};
      message: r.row.title,
      title: 'Deleted'                                //assign some functions that do nothing.
    });                                               handlers.click = function(r){};
    dialog.show();                                    handlers.deleteRow = function(r){};
  });
                                                      //expose a function that can pass in a reference
                                                      to an external function and assign the reference
                                                      to the appropriate handler.
                                                      exports.addEventListener = function(listenerName,
                                                      listenerFunction){
                                                         switch (listenerName){
In the main app we call the                                 case 'click' :

“addEventListener” function, passing in                        handlers.click = listenerFunction;
                                                               break;

the name of the listener and defining                        case 'delete' :
                                                               handlers.deleteRow = listenerFunction;
the function we want to execute when                           break;
                                                         };
the even is fired.                                     };

                                                      if(OS_IOS){
                                                         $.table.addEventListener('delete',
                                                      function(r){
CONTROLLERS – HANDLING EVENTS
             App – index.js                                 Widget – widget.js
  $.table1.addEventListener('delete', function(r){    //assign some functions that do nothing.
  Ti.API.info('row deleted: ' + JSON.stringify(r));   handlers.click = function(r){};
  var dialog = Ti.UI.createAlertDialog({              handlers.deleteRow = function(r){};
      message: r.row.title,
      title: 'Deleted'                                //expose a function that can pass in a reference
    });                                               to an external function and assign the reference
    dialog.show();                                    to the appropriate handler.
  });                                                 exports.addEventListener = function(listenerName,
                                                      listenerFunction){
                                                         switch (listenerName){
                                                            case 'click' :
                                                               handlers.click = listenerFunction;
                                                               break;
                                                            case 'delete' :
                                                               handlers.deleteRow = listenerFunction;
In the widget we listen for the table's                        break;
                                                         };
“delete” event and call the appropriate               };

handler object.                                       if(OS_IOS){
                                                         $.table.addEventListener('delete',
                                                      function(r){
                                                              handlers.deleteRow(r);	
                                                          });
                                                      };
THANK YOU

 Source code: http://bit.ly/alloy-customTableView

Slideshare: http://bit.ly/alloy-customTableViewSlides



             Mobile Data Systems Ltd.
            Turnkey mobile consultancy

            www.mobiledatasystems.co

      martin.hudson@mobiledatasystems.co

More Related Content

What's hot

Academy PRO: React native - navigation
Academy PRO: React native - navigationAcademy PRO: React native - navigation
Academy PRO: React native - navigationBinary Studio
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedToru Wonyoung Choi
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todaygerbille
 
Android development with Scala and SBT
Android development with Scala and SBTAndroid development with Scala and SBT
Android development with Scala and SBTAnton Yalyshev
 
Protocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupProtocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupNatasha Murashev
 
Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose worldFabio Collini
 
Workshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSWorkshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSVisual Engineering
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIVisual Engineering
 
Building scalable applications with angular js
Building scalable applications with angular jsBuilding scalable applications with angular js
Building scalable applications with angular jsAndrew Alpert
 
Academy PRO: React native - building first scenes
Academy PRO: React native - building first scenesAcademy PRO: React native - building first scenes
Academy PRO: React native - building first scenesBinary Studio
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesMichael Galpin
 
JSF Custom Components
JSF Custom ComponentsJSF Custom Components
JSF Custom ComponentsMichael Fons
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On RailsWen-Tien Chang
 

What's hot (20)

Academy PRO: React native - navigation
Academy PRO: React native - navigationAcademy PRO: React native - navigation
Academy PRO: React native - navigation
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO Extended
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of today
 
Android development with Scala and SBT
Android development with Scala and SBTAndroid development with Scala and SBT
Android development with Scala and SBT
 
Protocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS MeetupProtocol Oriented MVVM - Auckland iOS Meetup
Protocol Oriented MVVM - Auckland iOS Meetup
 
Workshop 15: Ionic framework
Workshop 15: Ionic frameworkWorkshop 15: Ionic framework
Workshop 15: Ionic framework
 
Extend sdk
Extend sdkExtend sdk
Extend sdk
 
Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
 
Workshop 17: EmberJS parte II
Workshop 17: EmberJS parte IIWorkshop 17: EmberJS parte II
Workshop 17: EmberJS parte II
 
ParisJS #10 : RequireJS
ParisJS #10 : RequireJSParisJS #10 : RequireJS
ParisJS #10 : RequireJS
 
Workshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSWorkshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJS
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte II
 
Building scalable applications with angular js
Building scalable applications with angular jsBuilding scalable applications with angular js
Building scalable applications with angular js
 
Academy PRO: React native - building first scenes
Academy PRO: React native - building first scenesAcademy PRO: React native - building first scenes
Academy PRO: React native - building first scenes
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
 
ExtJs Basic Part-1
ExtJs Basic Part-1ExtJs Basic Part-1
ExtJs Basic Part-1
 
JSF Custom Components
JSF Custom ComponentsJSF Custom Components
JSF Custom Components
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
 
Android 3
Android 3Android 3
Android 3
 
Rails Best Practices
Rails Best PracticesRails Best Practices
Rails Best Practices
 

Similar to Creating Alloy Widgets

How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)Giuseppe Filograno
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsHassan Abid
 
07_UIAndroid.pdf
07_UIAndroid.pdf07_UIAndroid.pdf
07_UIAndroid.pdfImranS18
 
Building a dashboard using AngularJS
Building a dashboard using AngularJSBuilding a dashboard using AngularJS
Building a dashboard using AngularJSRajthilakMCA
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of usOSCON Byrum
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
Adopting 3D Touch in your apps
Adopting 3D Touch in your appsAdopting 3D Touch in your apps
Adopting 3D Touch in your appsJuan C Catalan
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in AndroidRobert Cooper
 
Day 8: Dealing with Lists and ListViews
Day 8: Dealing with Lists and ListViewsDay 8: Dealing with Lists and ListViews
Day 8: Dealing with Lists and ListViewsAhsanul Karim
 
Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Fafadia Tech
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basicsAnton Narusberg
 
Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Fabio Biondi
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidNelson Glauber Leal
 
First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentNuvole
 
Already given code from 4 files- 1-app-ctrl-js code- -- include expres.pdf
Already given code from 4 files- 1-app-ctrl-js code- -- include expres.pdfAlready given code from 4 files- 1-app-ctrl-js code- -- include expres.pdf
Already given code from 4 files- 1-app-ctrl-js code- -- include expres.pdfas1mobiles
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
 
Android activity, service, and broadcast recievers
Android activity, service, and broadcast recieversAndroid activity, service, and broadcast recievers
Android activity, service, and broadcast recieversUtkarsh Mankad
 

Similar to Creating Alloy Widgets (20)

How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
07_UIAndroid.pdf
07_UIAndroid.pdf07_UIAndroid.pdf
07_UIAndroid.pdf
 
Building a dashboard using AngularJS
Building a dashboard using AngularJSBuilding a dashboard using AngularJS
Building a dashboard using AngularJS
 
Android L01 - Warm Up
Android L01 - Warm UpAndroid L01 - Warm Up
Android L01 - Warm Up
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of us
 
Android classes in mumbai
Android classes in mumbaiAndroid classes in mumbai
Android classes in mumbai
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
Adopting 3D Touch in your apps
Adopting 3D Touch in your appsAdopting 3D Touch in your apps
Adopting 3D Touch in your apps
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in Android
 
Day 8: Dealing with Lists and ListViews
Day 8: Dealing with Lists and ListViewsDay 8: Dealing with Lists and ListViews
Day 8: Dealing with Lists and ListViews
 
Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
 
Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no Android
 
First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven Development
 
Already given code from 4 files- 1-app-ctrl-js code- -- include expres.pdf
Already given code from 4 files- 1-app-ctrl-js code- -- include expres.pdfAlready given code from 4 files- 1-app-ctrl-js code- -- include expres.pdf
Already given code from 4 files- 1-app-ctrl-js code- -- include expres.pdf
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Android activity, service, and broadcast recievers
Android activity, service, and broadcast recieversAndroid activity, service, and broadcast recievers
Android activity, service, and broadcast recievers
 

Creating Alloy Widgets

  • 1. ALLOY WIDGETS Improving code re-use through a library of bespoke UI components. TiConf.eu Martin Hudson, Jonti Hudson February 2013
  • 2. WHAT IS A WIDGET? A self-contained bespoke UI component that holds all the logic associated with its use.
  • 3. WHAT IS A WIDGET? A self-contained bespoke UI component that holds all the logic associated with its use. • Create a re-usable library across multiple projects
  • 4. WHAT IS A WIDGET? A self-contained bespoke UI component that holds all the logic associated with its use. • Create a re-usable library across multiple projects • Create components that manage cross- platform differences (e.g. a table edit / delete component)
  • 5. WHAT IS A WIDGET? A self-contained bespoke UI component that holds all the logic associated with its use. • Create a re-usable library across multiple projects • Create components that manage cross- platform differences (e.g. a table edit / delete component) • Improve readability of code
  • 6. WHAT IS A WIDGET? A self-contained bespoke UI component that holds all the logic associated with its use. • Create a re-usable library across multiple projects • Create components that manage cross- platform differences (e.g. a table edit / delete component) • Improve readability of code • Improve reliability due to re-use of tested components.
  • 7. WHAT IS A WIDGET? App Widget Multiple widgets in the same window...
  • 8. WHAT IS A WIDGET? App Widget ... or multiple instances of the same widget
  • 9. A CUSTOM TABLE VIEW WIDGET An example of building a cross-platform widget that encapsulates common functionality but utilises platform specific behaviour.
  • 10. CREATING A WIDGET To create a new widget, right click the project name in the Titanium Studio project view... and select New → Alloy Widget.
  • 11. CREATING A WIDGET To create a new widget, right click the project name in the Titanium Studio project view... and select New → Alloy Widget. Use a “Reverse domain” naming convention to ensure widget names are not replicated when you share widgets with others.
  • 12. WIDGET FILE STRUCTURE A widgets folder is created with Controllers, Styles and Views sub-directories. Note the absence of Models – this is because the main app should handle data storage
  • 13. USING A WIDGET In the main app, we will call the newly created widget using the “Require” tag. App – index.xml Widget – widget.xml <Alloy> <Alloy> <Window class="container"> <TableView id="table"></TableView> <Require type="widget" </Alloy> src="co.mobiledatasystems.customEditableTable" id="table1"> </Require> <Button id="btnEdit" title="Allow Editing" onClick="btnEdit_click_Event"> </Button> </Window> </Alloy>
  • 14. USING A WIDGET In the main app, we will call the newly created widget using the “Require” tag. App – index.xml Widget – widget.xml <Alloy> <Alloy> <Window class="container"> <TableView id="table"></TableView> <Require type="widget" </Alloy> src="co.mobiledatasystems.customEditableTable" id="table1"> </Require> <Button id="btnEdit" title="Allow Editing" onClick="btnEdit_click_Event"> </Button> </Window> </Alloy> Note we specify that we want a widget and reference the name of our new widget. Alloy knows where to find it.
  • 15. USING A WIDGET In the main app, we will call the newly created widget using the “Require” tag. App – index.xml Widget – widget.xml <Alloy> <Alloy> <Window class="container"> <TableView id="table"></TableView> <Require type="widget" </Alloy> src="co.mobiledatasystems.customEditableTable" id="table1"> </Require> <Button id="btnEdit" title="Allow Editing" onClick="btnEdit_click_Event"> </Button> </Window> </Alloy> In the widget, we specify the UI components we want to expose. In our case it is only a TableView.
  • 16. STYLING App – index.tss Widget – widget.tss ".container": { backgroundColor:"white" }, "#table1": { left: '10dp', right: '10dp', top: '20dp', bottom:'80dp' }, "#btnEdit": { bottom:'10dp', left:'20dp', right:'20dp', height:'45dp' } We have referenced our instance of the widget “table1” in index.xml
  • 17. STYLING App – index.tss Widget – widget.tss ".container": { backgroundColor:"white" }, "#table1": { left: '10dp', right: '10dp', top: '40dp', bottom:'80dp' }, "#btnEdit": { bottom:'10dp', left:'20dp', right:'20dp', height:'45dp' } Note, where possible, do all the styling of widget components in the main app. This ensures maximum re-usability across projects.
  • 18. CONTROLLERS - INITIALISE App – index.tss Widget – widget.js //copy the arguments passed in to the widget via. ".container": { the xml and tss parameters backgroundColor:"white" }, var _args = arguments[0] || {}; "#table1": { var editable = null; left: '10dp', right: '10dp', if(OS_ANDROID){ top: '40dp', editable = false; bottom:'80dp' }; }, //get each element set in the widget's xml or tss "#btnEdit": { parameters bottom:'10dp', left:'20dp', Ti.API.info(JSON.stringify(_args)); right:'20dp', height:'45dp' //iterate round all the parameters we have passed } in for (var key in _args) { if (_args.hasOwnProperty(key)) { In the widget's controller we can //checks key is a direct property of _args, not access all the parameters passed in somewhere down the object tree using the arguments[] array. if(OS_ANDROID){ switch (key){
  • 19. CONTROLLERS - INITIALISE App – index.tss Widget – widget.js //copy the arguments passed in to the widget via. ".container": { the xml and tss parameters backgroundColor:"white" }, var _args = arguments[0] || {}; "#table1": { var editable = null; left: '10dp', right: '10dp', if(OS_ANDROID){ top: '40dp', editable = false; bottom:'80dp' }; }, //get each element set in the widget's xml or tss "#btnEdit": { parameters bottom:'10dp', left:'20dp', Ti.API.info(JSON.stringify(_args)); right:'20dp', height:'45dp' //iterate round all the parameters we have passed } in for (var key in _args) { if (_args.hasOwnProperty(key)) { In the widget's controller we can //checks key is a direct property of _args, not access all the parameters passed in somewhere down the object tree using the arguments[] array. if(OS_ANDROID){ switch (key){
  • 20. CONTROLLERS - INITIALISE App – index.tss Widget – widget.js //iterate round all the parameters we have passed ".container": { in backgroundColor:"white" }, for (var key in _args) { "#table1": { if (_args.hasOwnProperty(key)) { left: '10dp', right: '10dp', //checks key is a direct property of _args, not top: '40dp', somewhere down the object tree bottom:'80dp' }, if(OS_ANDROID){ "#btnEdit": { switch (key){ bottom:'10dp', case 'editing': left:'20dp', editable = _args[key]; right:'20dp', break; height:'45dp' case 'moving': break; //android } doesn't recognise this property default: We can read each parameter passed in } $.table[key] = _args[key]; and process them appropriately. In our } else { $.table[key] = _args[key]; example “editable” and “moving” are }; }; iOS specific. We will set a local }; variable in the case of Android.
  • 21. CONTROLLERS - INITIALISE App – index.tss Widget – widget.js //iterate round all the parameters we have passed ".container": { in backgroundColor:"white" }, for (var key in _args) { "#table1": { if (_args.hasOwnProperty(key)) { left: '10dp', right: '10dp', //checks key is a direct property of _args, not top: '40dp', somewhere down the object tree bottom:'80dp' }, if(OS_ANDROID){ "#btnEdit": { switch (key){ bottom:'10dp', case 'editing': left:'20dp', editable = _args[key]; right:'20dp', break; height:'45dp' case 'moving': break; //android } doesn't recognise this property default: We can read each parameter passed in } $.table[key] = _args[key]; and process them appropriately. In our } else { $.table[key] = _args[key]; example “editable” and “moving” are }; }; iOS specific. We will set a local }; variable in the case of Android.
  • 22. CONTROLLERS – CALLING FUNCTIONS App – index.js Widget – widget.js $.index.open(); //custom method we expose to set the table's data var editMode = false; exports.setData = function(rows /*Ti.UI.Row*/){ $.table.setData(rows); //create some data to put in the table }; var rows = []; for(var i=0;i<10;i++){ //custom method we expose to allow the table to rows.push(Ti.UI.createTableViewRow({title:'Row be editable number ' + i})); exports.editing = function(edit /*bool*/){ }; if(OS_IOS){ $.table1.setData(rows); //call the "setData" $.table.editing = edit; //allow row method we created in the widget editing on iPhone & iPad } else { //toggle the "editable" mode of the table editable = edit; function btnEdit_click_Event(){ }; if(editMode){ }; $.btnEdit.title = "Allow Editing"; editMode = false; } else { Using the commonJS framework, we $.btnEdit.title = "Cancel Editing"; editMode = true; can expose functions in the widget. In }; $.table1.editing(editMode); //call the our example we expose “setData” so "editing" method we created in the widget }; we can populate the table after the widget has created it.
  • 23. CONTROLLERS – CALLING FUNCTIONS App – index.js Widget – widget.js $.index.open(); //custom method we expose to set the table's data var editMode = false; exports.setData = function(rows /*Ti.UI.Row*/){ $.table.setData(rows); //create some data to put in the table }; var rows = []; for(var i=0;i<10;i++){ //custom method we expose to allow the table to rows.push(Ti.UI.createTableViewRow({title:'Row be editable number ' + i})); exports.editing = function(edit /*bool*/){ }; if(OS_IOS){ $.table1.setData(rows); //call the "setData" $.table.editing = edit; //allow row method we created in the widget editing on iPhone & iPad } else { //toggle the "editable" mode of the table editable = edit; function btnEdit_click_Event(){ }; if(editMode){ }; $.btnEdit.title = "Allow Editing"; editMode = false; } else { Using the commonJS framework, we $.btnEdit.title = "Cancel Editing"; editMode = true; can expose functions in the widget. In }; $.table1.editing(editMode); //call the our example we expose “setData” so "editing" method we created in the widget }; we can populate the table after the widget has created it.
  • 24. CONTROLLERS – CALLING FUNCTIONS App – index.js Widget – widget.js $.index.open(); //custom method we expose to set the table's data var editMode = false; exports.setData = function(rows /*Ti.UI.Row*/){ $.table.setData(rows); //create some data to put in the table }; var rows = []; for(var i=0;i<10;i++){ //custom method we expose to allow the table to rows.push(Ti.UI.createTableViewRow({title:'Row be editable number ' + i})); exports.editing = function(edit /*bool*/){ }; if(OS_IOS){ $.table1.setData(rows); //call the "setData" $.table.editing = edit; //allow row method we created in the widget editing on iPhone & iPad } else { //toggle the "editable" mode of the table editable = edit; function btnEdit_click_Event(){ }; if(editMode){ }; $.btnEdit.title = "Allow Editing"; editMode = false; } else { $.btnEdit.title = "Cancel Editing"; editMode = true; Here, the main app is responding to a }; $.table1.editing(editMode); //call the button click event and changing the "editing" method we created in the widget }; editable state in the widget.
  • 25. CONTROLLERS – CALLING FUNCTIONS App – index.js Widget – widget.js $.index.open(); //custom method we expose to set the table's data var editMode = false; exports.setData = function(rows /*Ti.UI.Row*/){ $.table.setData(rows); //create some data to put in the table }; var rows = []; for(var i=0;i<10;i++){ //custom method we expose to allow the table to rows.push(Ti.UI.createTableViewRow({title:'Row be editable number ' + i})); exports.editing = function(edit /*bool*/){ }; if(OS_IOS){ $.table1.setData(rows); //call the "setData" $.table.editing = edit; //allow row method we created in the widget editing on iPhone & iPad } else { //toggle the "editable" mode of the table editable = edit; function btnEdit_click_Event(){ }; if(editMode){ }; $.btnEdit.title = "Allow Editing"; editMode = false; } else { $.btnEdit.title = "Cancel Editing"; editMode = true; Here, the main app is responding to a }; $.table1.editing(editMode); //call the button click event and changing the "editing" method we created in the widget }; editable state in the widget.
  • 26. CONTROLLERS – HANDLING EVENTS App – index.js Widget – widget.js $.table1.addEventListener('delete', function(r){ //create a handlers object that will contain Ti.API.info('row deleted: ' + JSON.stringify(r)); references to functions var dialog = Ti.UI.createAlertDialog({ var handlers = {}; message: r.row.title, title: 'Deleted' //assign some functions that do nothing. }); handlers.click = function(r){}; dialog.show(); handlers.deleteRow = function(r){}; }); //expose a function that can pass in a reference to an external function and assign the reference In the widget we create an to the appropriate handler. “addEventListener” function that has exports.addEventListener = function(listenerName, listenerFunction){ two parameters, the name of the event switch (listenerName){ case 'click' : and a reference to the function it will handlers.click = listenerFunction; break; call in the main app. case 'delete' : handlers.deleteRow = listenerFunction; break; We assign the reference to a }; }; “handlers” object we created in the if(OS_IOS){ widget. $.table.addEventListener('delete', function(r){
  • 27. CONTROLLERS – HANDLING EVENTS App – index.js Widget – widget.js $.table1.addEventListener('delete', function(r){ //create a handlers object that will contain Ti.API.info('row deleted: ' + JSON.stringify(r)); references to functions var dialog = Ti.UI.createAlertDialog({ var handlers = {}; message: r.row.title, title: 'Deleted' //assign some functions that do nothing. }); handlers.click = function(r){}; dialog.show(); handlers.deleteRow = function(r){}; }); //expose a function that can pass in a reference to an external function and assign the reference to the appropriate handler. exports.addEventListener = function(listenerName, listenerFunction){ switch (listenerName){ In the main app we call the case 'click' : “addEventListener” function, passing in handlers.click = listenerFunction; break; the name of the listener and defining case 'delete' : handlers.deleteRow = listenerFunction; the function we want to execute when break; }; the even is fired. }; if(OS_IOS){ $.table.addEventListener('delete', function(r){
  • 28. CONTROLLERS – HANDLING EVENTS App – index.js Widget – widget.js $.table1.addEventListener('delete', function(r){ //assign some functions that do nothing. Ti.API.info('row deleted: ' + JSON.stringify(r)); handlers.click = function(r){}; var dialog = Ti.UI.createAlertDialog({ handlers.deleteRow = function(r){}; message: r.row.title, title: 'Deleted' //expose a function that can pass in a reference }); to an external function and assign the reference dialog.show(); to the appropriate handler. }); exports.addEventListener = function(listenerName, listenerFunction){ switch (listenerName){ case 'click' : handlers.click = listenerFunction; break; case 'delete' : handlers.deleteRow = listenerFunction; In the widget we listen for the table's break; }; “delete” event and call the appropriate }; handler object. if(OS_IOS){ $.table.addEventListener('delete', function(r){ handlers.deleteRow(r); }); };
  • 29. THANK YOU Source code: http://bit.ly/alloy-customTableView Slideshare: http://bit.ly/alloy-customTableViewSlides Mobile Data Systems Ltd. Turnkey mobile consultancy www.mobiledatasystems.co martin.hudson@mobiledatasystems.co