Archive for the ‘Flex Mobile’ Category

Flex Mobile : DateField 4 Mobile

Posted: September 1, 2011 in Flex Mobile

Need: Since Adobe has not yet released a spark “mobile optimized” DateField component to replace the mx:DateField component, I needed a solution fast for a touch-friendly DateField to use in my mobile tablet apps.

FlexTex GitRDone: This is my “GitRDone” workaround for now.  No custom components, No 3rd Party components.  Simple and Easy.  SOURCE FLEX PROJECT

1. I imported the mx.swc from my Flex 4.5.1 SDK into the library path of my Flex Mobile Project.  This is a back door to using mx inside a Mobile Project, which does not include the mx.swc . I added the mx namespace in my View.

2. Then, thanks to Peter Dehaan over at http://blog.flexexamples.com/ for examples on skinning mx:DateField, I changed the style  to make it more touch-friendly.  Increased the size of the calendar icon and the next/previous month icon.  I also increased the fontSize so the dates were big enough to select with finger.

3.  I tested it on the Xoom and the Acer Iconia tablets. Works great!  Here is how it looks on Motorola Xoom.

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" 
		xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView">
	
	<fx:Script>
		<![CDATA[	
			import mx.controls.DateChooser;
			
		]]>
	</fx:Script>
	
	
	<fx:Style>
		@namespace s "library://ns.adobe.com/flex/spark";
		@namespace mx "library://ns.adobe.com/flex/halo";
		@namespace components "components.*";
		
		.dfStyle
		{
			skin: Embed("calendarIcon48x48.png");
			upSkin: ClassReference(null);
			overSkin: ClassReference(null);
			downSkin: ClassReference(null);
			disabledSkin: ClassReference(null); 
		}
		
			.myDateChooserStyles {
				/* Previous Month */
			prevMonthUpSkin: Embed("touchButtonLeft.png");
			prevMonthOverSkin: Embed("touchButtonLeft.png");
			prevMonthDownSkin: Embed("touchButtonLeft.png");
			prevMonthDisabledSkin: Embed("touchButtonLeft.png");
			
			/* Next Month */
			nextMonthUpSkin: Embed("touchButtonRight.png");
			nextMonthOverSkin: Embed("touchButtonRight.png");
			nextMonthDownSkin: Embed("touchButtonRight.png");
			nextMonthDisabledSkin: Embed("touchButtonRight.png");
		}
		
		
	</fx:Style>
	<s:Panel title="My Form" width="100%" height="100%">
		<s:VGroup paddingRight="10" paddingLeft="10" paddingTop="10" paddingBottom="10" width="100%" height="100%">
		<s:Form>
		<s:FormItem  label="Start Date" fontSize="20">
			<mx:DateField id="date1"  interactionMode="touch" styleName="dfStyle" dateChooserStyleName="myDateChooserStyles"   fontSize="40" height="48" />
		</s:FormItem>
		<s:FormItem   label="End Date" fontSize="20">
			<mx:DateField id="date2"  styleName="dfStyle" dateChooserStyleName="myDateChooserStyles"   fontSize="40" height="48" />
		</s:FormItem>
		</s:Form>
		</s:VGroup>
		<s:controlBarContent>
			<s:Button label="Save" height="50"/>
		</s:controlBarContent>
	</s:Panel>
	
</s:View>

Want to grab your current GPS location, display it on a map and update the location as the device moves?
I took the basic example off of TourDeFlex and applied it to the new MapQuest Mobile Flash API.
I went with MapQuest Mobile because of the performance issues of Google Maps Flash API and Adobe Air.
Mapquest is working great for me and their developers are very responsive!
Works on Motorola Xoom, Acer Iconia, Blackberry Playbook, and iPad.
Here is my source code that in live on my Tablet apps.

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:tilemap="com.mapquest.tilemap.*"  creationComplete="initApp()" 
		 xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx"	width="100%" height="100%">
	<fx:Declarations>
		
	</fx:Declarations>
	
		<fx:Script>
			<![CDATA[
				import com.mapquest.Config;
				import com.mapquest.LatLng;
				import com.mapquest.mobile.GPS;
				import com.mapquest.tilemap.*;
				import com.mapquest.tilemap.controls.DefaultControlSet;
				import com.mapquest.tilemap.controls.shadymeadow.SMViewControl;
				import com.mapquest.tilemap.controls.shadymeadow.SMZoomControl;
				import com.mapquest.tilemap.pois.Poi;
				
				import flash.sensors.Geolocation;
				
				import mx.effects.easing.Circular;
				import mx.effects.easing.Elastic;
				
				import spark.components.View;
				import spark.events.ViewNavigatorEvent;
				
				
				private var isPinching:Boolean;
				private var currentCenter:LatLng;
				private var zoomControl:SMZoomControl;
				private var viewControl:SMViewControl = new SMViewControl();
				
				private var zs:ZoomSettings;
				
				import com.mapquest.*;
				import com.mapquest.mobile.GPS;
				import com.mapquest.mobile.TextUtil;
				import com.mapquest.tilemap.*;
				import com.mapquest.tilemap.pois.*;
				
				import mx.events.ResizeEvent;
				
				
				
				include "Config.as";
				
				
				[Bindable]
				public var map:TileMap;
				protected var g:Geolocation = new Geolocation();   
				public var gps:GPS;
				
				public var gpsSupported:Boolean;
				
				public var currentLatLng:LatLng = new LatLng(38.134557, -98.4375);
				//public var currentLatLng:LatLng;
				
				public var textUtil:TextUtil;
				
				private var gpsPoi:Poi;
				private var counter:Number = 0;
				
				private function initApp():void {
					makeMap();
					
					if (Geolocation.isSupported)
					{
						
						latitude.text = "Finding Location...";
						g.addEventListener(GeolocationEvent.UPDATE, onUpdate);
						addEventListener(ViewNavigatorEvent.REMOVING,onRemove);
					}
					else
					{
						
						latitude.text = "Geolocation is not supported on this device.";
					}    
					
					
					gps = new GPS();
					textUtil = new TextUtil();
					
					if (gps.isSupported) {
						gpsSupported = true;
						
					}
					else {
						this.gps = null;
					}
					
					
					
					
					this.addEventListener(ResizeEvent.RESIZE,this.onResize);
					
				}
			
				protected function onUpdate(event:GeolocationEvent):void
				{
					trace("Update event called");
					
					
					if(event.latitude){
						
						var ll:LatLng = new LatLng(event.latitude,event.longitude);
						currentLatLng = ll;
						latitude.text = event.latitude.toString();
						longitude.text = event.longitude.toString();
						counter = counter+1;
						
						gps.getCurrentLocation();
						
						if(gps.currentLatLng){
							currentLatLng = gps.currentLatLng;
						}
						else {
							currentLatLng = ll;
						}
						
						
						if(counter == 1){
							setPoi();
						}
						else {
							
							gpsPoi.latLng = currentLatLng;
						}
						
						
					}
					
				
					
				}
				
				private function setPoi():void {
					
					gpsPoi = new Poi(currentLatLng)
					gpsPoi.infoWindowTitleText = "Current Location";
					gpsPoi.infoContent = "LatLng: " + this.gpsPoi.latLng.toString();
					
					map.setCenter(currentLatLng,mapStartZoomLevel);	
					map.addShape(gpsPoi);
				}
				
				protected function onRemove(event:ViewNavigatorEvent):void
				{
					g.removeEventListener(GeolocationEvent.UPDATE, onUpdate);                
				}
				
				private function onResize(e:ResizeEvent):void {
					this.map.size = new Size(this.width,this.height);
				}
				
				
				private function makeMap():void {
					
					map = new TileMap(key,mapStartZoomLevel,currentLatLng,mapStartType);
					
					map.size = new Size(uic.width,this.uic.height);
					uic.addChild(map);
					map.mapFriction = mapFriction;
					
				}
					
				
			]]>
		</fx:Script>
	
	
	
	
	
	
	<mx:UIComponent id="uic" width="100%" height="100%" x="0" y="0"/>
	
	<s:HGroup top= "60" left="60">
		<s:Label text="Latitude:" color="0xffffff"/>
		<s:Spacer width="5" />
		<s:Label id="latitude" color="0xffffff"/>
		<s:Spacer width="50"/>
		<s:Label text="Longitude:" color="0xffffff"/>
		<s:Spacer width="5"/>
		<s:Label id="longitude" color="0xffffff"/>
		
	</s:HGroup>
	
</s:Group>

If you want to save something to external storage ( SD Card, USB) … A little thing you might miss.

In your App.xml file, you have uncomment this line in the Android Manifest .

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

In Texas, we have a lot of Oil and Gas Facilities both onshore and offshore.  They leak Green House Gases (GHG). One of my clients provides tools for testing and reducing GHG.  I built a Flex Mobile tablet application for them to take into the field.  It stores data offline since they don’t always have an internet connection.

Challenge was: What do you do if you drop the tablet on the rig and it smashes?  Do you lose all the test data captured on the tablet?  The solution I came up with is to copy the offline data stored on the device onto the SD card.  This would allow them to be able to move the data onto their backup tablet and continue on with the testing using the new device.

This function copies the Local SharedObject, that stores the offline data, onto the SD Card.


public function soToSD():void {

var soOnSD:File = File.documentsDirectory.resolvePath("mGHG.sol");

var soDir:String = File.applicationStorageDirectory.resolvePath("#SharedObjects").nativePath;

var soInAppStorage:File = new File(soDir);

soInAppStorage = soInAppStorage.resolvePath('mGHG2.swf/mGHG.sol');

soInAppStorage.copyTo(soOnSD, true);

var files:Array = File.documentsDirectory.getDirectoryListing();

for (var i:uint = 0; i &lt; files.length; i++) {

trace(files[i].nativePath);

}

}