PageRenderTime 43ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/content/programming/as3/as3-madcomponents-tutorial-series-tablet-and-phone-in-one.md

https://gitlab.com/monkmartinez/blog
Markdown | 319 lines | 260 code | 59 blank | 0 comment | 0 complexity | 66232f504b6f0f9b951e00bdf331e445 MD5 | raw file
  1. Title: AS3 MadComponents Tutorial Series - Tablet and Phone in One!
  2. Date: 2011-09-12
  3. Author: Michael
  4. This tutorial will demonstrate both tablet and phone layout in one
  5. ActionScript 3 Flash application for mobile. We will utilize the
  6. powerful [MadComponents library][] to quickly and easily add an amazing
  7. spilt screen view for the tablet. Then we will basically recycle the
  8. phone tutorial shown in the previous [separation of concerns
  9. tutorial][].
  10. Tablets such as the iPad and Android variants have quite a bit more
  11. screen real estate to work with. We can literally replicate a desktop
  12. experience with the tablet resolutions we are seeing today. So what
  13. should we do with all of this real estate? The answer to that question
  14. is; It depends. I know that is a bit of a cop-out, but we can not
  15. realistically attempt to cover every situation.
  16. This app will determine the screen resolution and choose the best layout
  17. to initialize. The table will utilize the popular split-view pattern for
  18. the tablet with a list control on the left side and content on the
  19. right. The phone layout consists of list based navigation as shown in
  20. the previous [example.][separation of concerns tutorial]
  21. DISCLAIMER: The colors used are ATROCIOUS. I did this to make absolutely
  22. sure the tutorial-ee can see what colors are used and where. Its a bit
  23. confusing and you'll need to experiment anyway.
  24. The SRC files can be downloaded [HERE][].
  25. Lets get this party started:
  26. :::as3
  27. package
  28. {
  29. import com.danielfreeman.madcomponents.*;
  30. import flash.desktop.NativeApplication;
  31. import flash.display.Sprite;
  32. import flash.display.StageAlign;
  33. import flash.display.StageScaleMode;
  34. import flash.events.Event;
  35. import flash.events.KeyboardEvent;
  36. import flash.events.MouseEvent;
  37. import flash.system.Capabilities;
  38. import flash.ui.Keyboard;
  39. public class SplitViewMAD extends Sprite
  40. {
  41. //////////////////////////// DATA FOR BOTH APPLICATIONS ////////////////////////////
  42. protected static const DATA:XML = <data>
  43. <item label="List Item 1"/>
  44. <item label="List Item 2"/>
  45. <item label="List Item 3 (this wrapping text; test test test test)"/>
  46. <item label="List Item 4"/>
  47. </data>;
  48. //////////////////////////// END DATA //////////////////////////////////////////////
  49. /////////////////////////// TABLET XML DEFINITION //////////////////////////////////
  50. // List can also be masked for a wrapping effect
  51. protected static const SPLITVIEW:XML = <columns stageColour="#A15D6F" id="myCols" gapH="4" widths="36%, 64%" background="#707449">
  52. <vertical id="myScroll" background="#E4D1B0"><list id="myList" colour="#c10000" autoLayout="true"><search colour="#D66821" field="label"/>{DATA}<label id="label" alignH="fill"/></list></vertical>
  53. <pages id="myPages">{Page0.LAYOUT}{Page1.LAYOUT1}{Page2.LAYOUT2}{Page3.LAYOUT3}</pages>
  54. </columns>;
  55. protected var _page:UIPages;
  56. /////////////////////////// END TABLET ///////////////////////////////////////////////
  57. /////////////////////////// PHONE XML DEFINITIONS ///////////////////////////////////
  58. protected static const LIST:XML = <list colour="#999999" background="#DADED4"><search colour="#DADED4" field="label"/>{DATA}</list>;
  59. // Each additional "Page" needs to have different id's for the components, even when they are separated into separate classes
  60. protected static const NAVIGATION:XML = <navigation id="nav" colour="#C100000" clickColour="#C100000" title="Phone Nav">
  61. {LIST}
  62. {Page0.LAYOUT}
  63. {Page1.LAYOUT1}
  64. {Page2.LAYOUT2}
  65. {Page3.LAYOUT3}
  66. </navigation>;
  67. protected var _uiNavigation:UINavigation;
  68. protected var _list:UIList;
  69. ////////////////////////////// END PHONE //////////////////////////////////////////////
  70. ///////////////////////////// INDEPENDENT CLASS VARS //////////////////////////////////
  71. protected var _resY:int = Capabilities.screenResolutionX;
  72. protected var _resX:int = Capabilities.screenResolutionY;
  73. protected var _dpi:int = Capabilities.screenDPI;
  74. ///////////////////////////// END CLASS VARS //////////////////////////////////////////
  75. The comments should visually separate the XML. The order in which you
  76. define this data is absolutely inconsequential.
  77. The DATA constant is used for both layouts. I'm quite sure there are a
  78. myriad of optimizations you could make here, but I wanted to make this
  79. as clear as possible for the uninitiated.
  80. Lets concentrate on the SPLITVIEW constant for a bit. The root node or
  81. tag is **columns**. We can use any numbers we like here. 36% for the
  82. left column and 64% for the right looked good on my Galaxy Tab 10.1
  83. Android tablet.
  84. After columns, you'll see the <vertical> node and it is the container
  85. for the left column. I choose to define the list here. You can get
  86. really creative and add images and/or other components in this column.
  87. The main thing to consider is text wrapping. If you aren't careful or
  88. have long labels, the text will spill onto the next column. In this
  89. case, I set **autoLayout = true** in the list node. Then we define the
  90. actual label node contained in the DATA constant with this tag; \< label
  91. id="label" alignH="fill" /\>. This will make your text wrap nice and
  92. neat.
  93. The right column is defined in the \< pages \> node. This, again, can be
  94. any node you'd like for your particular application but page worked well
  95. for this example. Note that we once again defined our pages outside this
  96. class and call them by their LAYOUT constant, then initialize them in a
  97. later method. You don't need to specify LAYOUT followed by a number, as
  98. LAYOUT or any other name will work just as well. I do that because,
  99. again, my brain works best with everything separated as cleanly as
  100. possible.
  101. The independent class vars grab the screen resolution in the X and Y
  102. axis and also provide the screen DPI. This will enable us to make the
  103. right decision on which layout we like to display.
  104. Lets move onto the constructor:
  105. :::as3
  106. //////////////////////////// CONSTRUCTOR /////////////////////////////////////////////
  107. public function SplitViewMAD(screen:Sprite = null) {
  108. if (screen){
  109. screen.addChild(this);
  110. }
  111. trace("Screen Resolution is " + _resX + "x" + _resY + " at " + _dpi + "ppi");
  112. // support autoOrients
  113. stage.align = StageAlign.TOP_LEFT;
  114. stage.scaleMode = StageScaleMode.NO_SCALE;
  115. // If the screen in the Y-axis is larger than 855px init tablet layout
  116. if(_resY >= 855){
  117. initializeTablet();
  118. }
  119. // If the screen in the Y-axis is smaller than 855px init Phone layout
  120. if(_resY <= 855){
  121. //Register the back button listener in constructor before UI.create and all is well
  122. stage.addEventListener(KeyboardEvent.KEY_DOWN, goBackButton);
  123. initializePhone();
  124. }
  125. }
  126. This constructor simply chooses to initialize the phone or tablet based
  127. on the resolution in the Y-axis. The number I decided to use for a break
  128. over is 855px because I'm testing on the OG Droid-1 (480x854) and a
  129. Galaxy 10.1 tablet (800 x 1290). I needed a way to make sure that the
  130. proper layout is initializing (you know, that it actually works). A more
  131. robust switch statement or if/else block is absolutely more appropriate
  132. in a real world scenario based on the devices one is targeting.
  133. The only gotcha here is the physical Android back button in the
  134. initializePhone block. The physical Android back button listener needs
  135. to be called before UI.create, which is in the initializePhone method,
  136. to work properly.
  137. In the interest of keeping all the logic available to copy and paste
  138. here is the phone logic. Note: its not materially different than the
  139. [previous tutorial][separation of concerns tutorial].
  140. :::as3
  141. ////////////////////// PHONE ////////////////////////
  142. private function initializePhone():void
  143. {
  144. // Create the main UI or "Landing Page"
  145. UI.create(this, NAVIGATION);
  146. // Initialize "views"
  147. // Initialize "views"
  148. Page0.initialize();
  149. Page1.initialize();
  150. Page2.initialize();
  151. Page3.initialize();
  152. // Navigation layout and behaviour
  153. _uiNavigation = UINavigation(UI.findViewById("nav"));
  154. _uiNavigation.autoForward = false;
  155. _uiNavigation.autoBack = false;
  156. // Change page handler
  157. _uiNavigation.addEventListener(UIList.CLICKED, navigationChange);
  158. _uiNavigation.navigationBar.backButton.addEventListener(MouseEvent.MOUSE_UP, goBack);
  159. // Nav back button color
  160. _uiNavigation.navigationBar.backButton.colour = 999999;
  161. }
  162. // Handles List item clicks
  163. public function navigationChange(event:Event):void {
  164. var navIndex:int = _uiNavigation.index;
  165. // Check to see if current page is @ 0 to set correct title
  166. if(_uiNavigation.pages[0]){
  167. _uiNavigation.title = "Phone Nav";
  168. }
  169. // navigation logic
  170. if(navIndex == 0){
  171. _uiNavigation.goToPage(2, UIPages.SLIDE_LEFT);
  172. _uiNavigation.title = "Page 1";
  173. } else if (navIndex == 1){
  174. _uiNavigation.goToPage(3, UIPages.SLIDE_LEFT);
  175. _uiNavigation.title = "Page 2";
  176. }else if (navIndex == 2){
  177. _uiNavigation.goToPage(4, UIPages.SLIDE_LEFT);
  178. _uiNavigation.title = "Page 3";
  179. }
  180. }
  181. // Nav bar back button
  182. protected function goBack(event:Event):void {
  183. var navIndex:int = _uiNavigation.index;
  184. _uiNavigation.goToPage(0, UIPages.SLIDE_RIGHT);
  185. _uiNavigation.title = "Phone Nav";
  186. trace("NavBar Event fired");
  187. }
  188. // Device back button handler
  189. protected function goBackButton(event:KeyboardEvent):void
  190. {
  191. // With autoBack set to false, you lose the back button for some reason
  192. // You can use the Native App library to hard check a back button press
  193. var navIndex:int = _uiNavigation.index;
  194. if(event.keyCode == Keyboard.BACK){
  195. _uiNavigation.goToPage(0, UIPages.SLIDE_RIGHT);
  196. _uiNavigation.title = "Phone Nav";
  197. trace("Keyboard event fired");
  198. }
  199. }
  200. //////////////////////// END PHONE /////////////////////////////
  201. Next we'll look at the tablet specific code:
  202. :::as3
  203. /////////////////////// TABLET ////////////////////////////////
  204. private function initializeTablet():void
  205. {
  206. // Create the main UI or "Landing Page"
  207. UI.create(this, SPLITVIEW);
  208. // Initialize "views"
  209. Page0.initialize();
  210. Page1.initialize();
  211. Page2.initialize();
  212. Page3.initialize();
  213. // Add the list
  214. _list = UIList(UI.findViewById("myList"));
  215. _list.addEventListener(UIList.CLICKED, changePage);
  216. // Add the pages component
  217. _page = UIPages(UI.findViewById("myPages"));
  218. }
  219. protected function changePage(event:Event):void
  220. {
  221. // TODO: holder page @ index 0 in DATA constant so first page is 1 and second is two. Holder will have a cool logo or something
  222. var index:int = _list.index;
  223. // Navigation logic
  224. if(index == 0){
  225. _page.goToPage(1,UIPages.SLIDE_RIGHT);
  226. } else
  227. if (index == 1){
  228. _page.goToPage(2,UIPages.SLIDE_RIGHT);
  229. } else
  230. if (index == 2){
  231. _page.goToPage(3,UIPages.SLIDE_RIGHT);
  232. }
  233. }
  234. ////////////////////// END TABLET ////////////////////////////////
  235. }
  236. }
  237. We call UI.create and pass in the SPLITVIEW constant. This is the
  238. MadComponents standard, so if don't get it... I suggest you to have a go
  239. with the other tutorials on [Daniels][MadComponents library] site or
  240. mine. Next, we initialize all the pages that reside outside of this
  241. class, but are defined in the pages node.
  242. We need a way to capture the clicks for the list on the left. So we
  243. instantiate a UIList variable to hold the list data. We then assign a
  244. click listener to the list variable. We also need a mechanism to
  245. navigate the pages once we've determined which list item has been
  246. clicked. So, again we assign a UIPages variable to hold and act on that
  247. data. This is all handled in the changePage event handler which is
  248. relatively self explanatory. I'm still working on the Android back
  249. button for this block. I will update it once I get it handled.
  250. I hope this helps you visualize what is possible with tablets and the
  251. ActionScript3 MadComponent Library. Expect more tutorials to follow!
  252. **This is a screen shot of the tablet running this app:**
  253. ![Tablet Split View][]
  254. **This is a screen shot of the phone running this app:**
  255. ![Phone Split View][]
  256. [MadComponents library]: http://madskool.wordpress.com/
  257. [separation of concerns tutorial]: http://caffeineindustries.com/?p=234
  258. [HERE]: http://www.mediafire.com/file/d4sbql4o0x44uhd/src.zip
  259. [Tablet Split View]: http://caffeineindustries.com/wp-content/uploads/2011/09/splitviewtablet800.png
  260. [Phone Split View]: http://caffeineindustries.com/wp-content/uploads/2011/09/device-2011-09-12-134809.png