Archive for the ‘Flex’ tag
OAuth authorization with Flash and Flex apps
Below you will find links to my two video tutorials about OAuth authorization with Flash and Flex apps:
1) Introduction to OAuth for secure user and application authorization
2) OAuth in Adobe AIR applications built with Flash or Flex
You can also download example code from here.
Slide effect with ViewStack and state transitions
In this post I want to explain how the slide effect can be applied to application views. My goal is to do it in a declarative way as much as possible and to use default Flex components. I will demonstrate two possible solutions, one using the ViewStack component and other using Flex states and transitions.
You may wonder why I put that much effort into the slide effect. Ok, I know this isn’t anything revolutionary and this type of user experience is quite common, but I think recently it has become even more popular. This is due to the fact that it is almost a standard type of view transition effect on mobile devices. Now why not try to bring some of the coolness of mobile interactions also to the desktop world?
Using the ViewStack component
In my previous post about the as3viewnavigator library I briefly mentioned a ViewStack component and its inability to display two views at the same time. The consequence of this is also an inability to have a slide effect similar to the one in ViewNavigator. It’s not that the slide effect is not possible at all but you can’t have two views slide together. The only available option in the default ViewStack implementation is to have one view slide out and when its hide effect finishes, to have second view slide in. This is demonstrated in the example below.
The implementation of this example is really very simple and you can see it below:
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="300" height="300" viewSourceURL="srcview/index.html" backgroundColor="#F0F0F0"> <fx:Declarations> <s:Move id="view1ShowEffect" xFrom="{-stack.width}" xTo="0" /> <s:Move id="view1HideEffect" xFrom="0" xTo="{-stack.width}" /> <s:Move id="view2ShowEffect" xFrom="{stack.width}" xTo="0" /> <s:Move id="view2HideEffect" xFrom="0" xTo="{stack.width}" /> </fx:Declarations> <mx:ViewStack id="stack" left="10" top="10" right="10" bottom="10"> <s:NavigatorContent id="view1" hideEffect="{view1HideEffect}" showEffect="{view1ShowEffect}"> <s:Button label="Show View 2" click="stack.selectedChild = view2" verticalCenter="0" horizontalCenter="0" /> </s:NavigatorContent> <s:NavigatorContent id="view2" hideEffect="{view2HideEffect}" showEffect="{view2ShowEffect}"> <s:Button label="Show View 1" click="stack.selectedChild = view1" verticalCenter="0" horizontalCenter="0" /> </s:NavigatorContent> </mx:ViewStack> </s:Application>
Using Flex states and transitions
Now with the states and transitions example I wanted to raise the bar a little bit. Still the goal was to slide the views but the first thing I wanted was to slide them at the same time, and second I wanted my target states to have only one view at a time. You may say this is not possible. Well not exactly. What if I introduced an additional state that was only used during the transition and it included both views for that short period of time? Check out the example below:
In the following code snippet you can see that I declared two additional states:
slideToView1State and slideToView2State. These states will actually serve when slide effects are applied. Also when you want to switch, for example to state view2State you would set the application’s currentState property to slideToView2State. When the transition from view1State to slideToView2State is finished the effectEnd event will be handled and it automatically changes the state to view2State.
Another interesting thing to note here is that the slide states are grouped in a slideStates state group and the two views don’t have to explicitly be included in slideToView1State and slideToView2State states.
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="300" height="300" viewSourceURL="http://riaspace.com/examples/ViewSlideTransitions/srcview/index.html" backgroundColor="#F0F0F0"> <s:states> <s:State name="view1State" /> <s:State name="slideToView2State" stateGroups="slideStates" /> <s:State name="view2State" /> <s:State name="slideToView1State" stateGroups="slideStates" /> </s:states> <s:transitions> <s:Transition fromState="view1State" toState="slideToView2State"> <s:Parallel effectEnd="currentState = 'view2State'"> <s:children> <s:Move id="hideView1Effect" target="{view1}" xTo="{-view1.width}" /> <s:Move id="viewShow2Effect" target="{view2}" xFrom="{view2.width}" xTo="0" /> </s:children> </s:Parallel> </s:Transition> <s:Transition fromState="view2State" toState="slideToView1State"> <s:Parallel effectEnd="currentState = 'view1State'"> <s:children> <s:Move id="showView1Effect" target="{view1}" xFrom="{-view1.width}" xTo="0" /> <s:Move id="hideView2Effect" target="{view2}" xTo="{view2.width}" /> </s:children> </s:Parallel> </s:Transition> </s:transitions> <s:Group id="view1" includeIn="view1State, slideStates" width="100%" height="100%"> <s:Button id="btnView1" label="Slide To View 2" click="currentState = 'slideToView2State'" horizontalCenter="0" verticalCenter="0" /> </s:Group> <s:Group id="view2" includeIn="view2State, slideStates" width="100%" height="100%"> <s:Button id="btnView2" label="Show View 1" click="currentState = 'slideToView1State'" horizontalCenter="0" verticalCenter="0" /> </s:Group> </s:Application>
as3viewnavigator 2.0.0 RC1 released!
I’m proud to announce a new release of the as3viewnavigator library. This new release is labeled with a 2.0.0 RC1 version number. Since the previous release the source code has been almost entirely rewritten to provide a host of new features, many bug-fixes and increased extensibility. The changes have likely also introduced some new bugs, so that is why this is an RC1 (Release Candidate 1) even though I think it is feature complete. Before it goes final I want to test it myself in battle and also have others provide input and bug reports. If you used previous versions I’m certain it will break your existing code (for your reference, the previous version is still available in github under the 1.0.0 tag.
So what is new:
- You can use
ViewNavigatorfor Flex (desktop) projects! At least until ViewNavigator from Flex Hero will not be available for desktop projects
ViewNavigatorhas become a container (based on the Sprite class for AS3 projects and theUIComponentfor Flex) now. Its default behavior in AS3 projects when added to the stage is that it takes 100% of the stage area and it auto-resizes itself. You also have an option to controlViewNavigatorwidth and height values explicitly. When using Flex you can lay it out anywhere in your MXML declaration like any other Flex component.- Default implementations of the
IViewinterface calledVieware provided for both AS3 (based onSprite) and Flex (based onSkinnableContainer) projects. - When performing actions on
ViewNavigator(like pop, push, etc.) aViewNavigatorEvent.VIEW_CHANGINGevent is dispatched. This event is cancelable so application logic can prevent the view change. Also the event has additional properties likeoldViewandnewViewwhich enable access to the instances of exchanged views. - It is now possible to add custom view transitions. This can be done by implementing the
IViewTransitioninterface and setting its implementation instance to theViewNavigatorobject’sdefaultTransitionproperty or by passing it to theViewNavigatorobject’s action functions. - View instances managed by
ViewNavigatorcan be destructed when they are no longer on the top of the stack. This can be controlled with a new property inIViewinterface nameddestructionPolicy. This property has two possible valuesautoandneverthat are also available in theViewDestructionPolicyenum class. DefaultIViewimplementations have this property set toauto.
Using it with Flex (desktop) projects:
Actually this is the feature I’m most excited about. You may wonder why this is since Flex already comes with the ViewStack component and ViewNavigator available in Flex Hero mobile projects. The reason is that the ViewStack doesn’t allow two views to be visible at the same time so this type of nice slide transition is not possible (at least the transition in which two views slide in at the same time, I will blog about this in my next post). And as I mentioned already the Flex Hero ViewNavigator is not available for desktop projects, at least not yet. Of course there is a third option, using state transitions, but it doesn’t come with an API as well thought through as the one in ViewNavigator.
Below you can see it working with Flex (right-click to access the example source code):
In the Main MXML document you can see that ViewNavigator can be treated like any other Flex component. It also has the set of properties that set up the first view and register the ViewNavigatorEvent.VIEW_CHANGING event handler. In the snippet below SampleView is registered as firstView and the viewNumber property of the first view instance is set to 1.
// Main.mxml <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:vn="http://ns.riaspace.com/as3viewnavigator" width="350" height="350" viewSourceURL="http://riaspace.com/examples/as3viewnavigator/flex/srcview/index.html"> <fx:Script> <![CDATA[ import com.riaspace.as3viewnavigator.demo.SampleView; import com.riaspace.as3viewnavigator.events.ViewNavigatorEvent; protected function navigator_viewChangingHandler(event:ViewNavigatorEvent):void { txtTrace.appendText( "action: " + event.action + ", oldView: " + event.oldView + " newView: " + event.newView + "\n" ); } ]]> </fx:Script> <s:VGroup left="5" top="5" right="5" bottom="5"> <vn:ViewNavigator id="navigator" firstView="{SampleView}" firstViewProps="{{viewNumber : 1}}" viewChanging="navigator_viewChangingHandler(event)" width="100%" height="70%" /> <s:Label id="lblTrace" text="Navigator events:" /> <s:TextArea id="txtTrace" width="100%" height="30%" /> </s:VGroup> </s:Application>
The SampleView MXML document extends the View class that comes with as3viewnavigator for Flex. Within the SampleView there are five buttons declared that let you play with ViewNavigator action functions. The code also declares the public viewNumber property that is set by the view that pushed the current view to the top of the stack. The value of the viewNumber property is 1 more than the viewNumber property from the previous view.
// com/riaspace/as3viewnavigator/demo/SampleView.as <?xml version="1.0" encoding="utf-8"?> <vn:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:vn="http://ns.riaspace.com/as3viewnavigator"> <fx:Script> <![CDATA[ import mx.utils.NameUtil; override public function toString():String { return NameUtil.createUniqueName(this); } ]]> </fx:Script> <fx:Declarations> <fx:Number id="viewNumber" /> </fx:Declarations> <s:Rect width="100%" height="100%"> <s:fill> <s:SolidColor color="#f0f0f0" /> </s:fill> </s:Rect> <s:Label id="lblViewNumber" text="{viewNumber}" fontSize="55" top="10" horizontalCenter="0" /> <s:VGroup bottom="10" horizontalCenter="0"> <s:Button id="btnPushView" label="push view" width="100" click="navigator.pushView(SampleView, {viewNumber : (viewNumber + 1)})" /> <s:Button id="btnPopView" label="pop view" width="100" click="navigator.popView()" /> <s:Button id="btnPopAll" label="pop all" width="100" click="navigator.popAll()" /> <s:Button id="btnPopToFirst" label="pop to first" width="100" click="navigator.popToFirstView()" /> <s:Button id="btnReplace" label="replace" width="100" click="navigator.replaceView(SampleView, {viewNumber : (viewNumber + 1)})" /> </s:VGroup> </vn:View>
Using it with AS3 projects:
The example below shows the AS3 version in action. You can also right-click it to access the full source code.
In this example, the ViewNavigator is instantiated and added as a child of the Main class (the Main class listing is below this paragraph). The ViewNavigator constructor receives two parameters: the class type of the first view (SampleView) to display and an Object with view properties to be set (in this case, this is my custom viewNumber property, which will be displayed in the view label). Before ViewNavigator is added as a child to the Main class it also registers a ViewNavigatorEvent.VIEW_CHANGING event handler that traces out info about ViewNavigator actions. Another thing to note here is that the ViewNavigator size is set explicitly in the layoutComponents function using setSize function. It is important to understand that in this situation ViewNavigator will not auto-size itself anymore to the size of the stage. That is why layoutComponents function is also called by stage Event.RESIZE event handler.
// Main.as package { import com.adobe.viewsource.ViewSource; import com.riaspace.as3viewnavigator.ViewNavigator; import com.riaspace.as3viewnavigator.demo.SampleView; import com.riaspace.as3viewnavigator.events.ViewNavigatorEvent; import fl.controls.TextArea; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; [SWF(width="350", height="350", frameRate="30")] public class Main extends Sprite { private var navigator:ViewNavigator; private var txtTrace:TextArea; public function Main() { // Adding source code view ViewSource.addMenuItem(this, "http://riaspace.com/examples/as3viewnavigator/as3/srcview/index.html"); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; // Adding trace area txtTrace = new TextArea; // Creating instance of ViewNavigator navigator = new ViewNavigator(SampleView, {viewNumber : 1}); // Registering view navigator event handler navigator.addEventListener(ViewNavigatorEvent.VIEW_CHANGING, navigator_viewChangingHandler); // Setting components dimenstions and positions layoutComponents(); // Adding txtTrace component addChild(txtTrace); // Adding navigator to the current sprite addChild(navigator); // Adding resize handler to handle components layout stage.addEventListener(Event.RESIZE, function(event:Event):void { layoutComponents() }); } protected function layoutComponents():void { // Resizing txtTrace component txtTrace.width = stage.stageWidth; // Setting fixed height of txtTrace component txtTrace.height = 60; // Positioning txtTrace component below navigator txtTrace.y = stage.stageHeight - txtTrace.height; // Setting navigator size to be over txtTrace component navigator.setSize(stage.stageWidth, stage.stageHeight - txtTrace.height); } protected function navigator_viewChangingHandler(event:ViewNavigatorEvent):void { txtTrace.appendText( "action: " + event.action + ", oldView: " + event.oldView + " newView: " + event.newView + "\n" ); } } }
The SampleView class extends View, which is a default implementation of the IView interface. Because the View class extends Sprite you can add/remove child DisplayObjects to/from it and work with it as with a standard Sprite. Worth mentioning here is overridden function resize. Doing so allows to scale and layout child elements of the view whenever the owning ViewNavigator size changes.
// com/riaspace/as3viewnavigator/demo/SampleView.as ... override public function resize():void { for (var element:Object in _elements) { var coordinates:Object = _elements[element]; position(DisplayObject(element), coordinates.horizontalCenter, coordinates.verticalCenter); } } ...
ADC tutorial: Updating Adobe AIR applications packaged with a native installer
My tutorial about updating AIR apps packaged with a native installer was published on Adobe Developer Connection – it is available here.
It goes step-by-step through how a custom updater can be built for Windows; it also explains how a similar process could be applied for the Mac OS X platform.
This tutorial is also a good starting point to understand how my NativeApplicationUpdater library works.
Screencast with Toaster Lite tour
Today I recorded a screencast of a Toaster Lite tour; it quickly demonstrates how the application works and how to use it.
Toaster Lite – HTTP/AMF monitoring tool
My little pet project called Toaster Lite has finally reached the point at which I can share it with the world. In its current state it is just a simple HTTP/AMF monitoring tool that lets you introspect your client-server traffic when doing your Flash/Flex development.
You may wonder why I built it. Well first of all I thought that it would be a cool example of what you can do with the ServerSocket API that came with AIR 2. Secondly I wanted to get better understanding of AMF (Action Message Format) structure. And, last and not least I have further plans for it and what I would like to achieve at some stage is functionality similar to soapUI but for AMF. (BTW: did you know that soapUI has some basic support for AMF but obviously not enough for me
)
So what I’m planning for the next release is the ability to create test suites and test cases based on monitored requests and being able to replay these accordingly. At some point I would like to be able to perform load/stress testing of AMF services with it. I know this is something that would require threading support but maybe the Flash Player team will solve this somehow. If not, I may endup using Java to do this part of the job and integrate it with the UI using Flerry.
When building Toaster I managed to extract part of it into a separate as3 library called amf-message-deserializer, which can deserialize AMF requests received through the ServerSocket. The library project is available here in GitHub. I want to credit my fellow evangelist James Ward for his JSAMF project, which was a great help and a starting point. Other good resources to really understand AMF0 and AMF3 are their open specs available through this site.
To install Toaster Lite just use the badge below:
UPDATED 2011.01.13 – recorded a screencast with Toaster Lite tour:
Resicon – icons batch resizing tool
Last night when I was working on my pet project (very soon to be released
) I finally got annoyed enough to take 15 minutes off to create this simple utility tool called Resicon. It is an icon batch resizing utility application. It allows you to resize icon images into a predefined set of sizes like: 16×16, 32×32, 36×36, 48×48, 72×72 and 128×128 or use a custom one.
This is a very handy tool because whenever you build an AIR application either a desktop or a mobile one you have to specify a set of its icons in different sizes. Usually this is done by downscaling a single high resolution image to the required sizes. This repetitive task is really annoying and that is why Resicon was brought to life.
Below is an install badge for the Resicon application, the source code is available in GitHub here.
BTW: Resicon icon was created with the very cool Icon Generator Pro app.
Paged list loaded from sqlite in Adobe AIR
During my recent work on the Adobe Evangelists Blogroll application I wanted to implement a lazy-loaded/paginated List component with data coming from a local SQLite database. The reason for this was, of course, a memory usage consideration. Adobe Evangelists Blogroll is a mobile application so I didn’t want to load all available Post objects for each selected blog at once. I wanted it to be loaded dynamically as the user scrolls through the list. It turned out this wasn’t really difficult but there were few gotchas that I wanted to share:
- You have to implement your own
IListcomponent that throwsItemPendingErrorwhenever the item requested withgetItemAtfunction is not available yet. Unfortunately the Flex SDK doesn’t come with one built-in, but the good news is that you can usePagedArrayListclass I created; its source code is available here
- Implement a
createPendingItemFunctionfor theAsyncListViewcomponent. This function gets called whenItemPendingErroris thrown and in our case serves two purposes. One is to trigger fetching the next page of rows from the database. It also returns aStringwith text that will be displayed temporarily in missing rows of theList. When that data gets fetched from the database those missing rows will be replaced with the loaded ones. - One gotcha for the previous point is that if you are using
SQLConnectionin synchronous mode you will have to start fetching rows in the next frame after the call to thecreatePendingItemFunctionfunction. That is why in my example I’m usingcallLaterto execute thefetchRowsfunction. This problem doesn’t arise with an asynchronous database connection. - The last gotcha is most likely a bug in the Flex SDK. It occurs when the
AsyncListView.listproperty is set before its list object is initialized and its length value is set. In that caseinvalidIndexerror is thrown inside of LinearLayoutVector. The workaround I came up with is that right after setting the length property,PagedArrayListdispatchesFlexEvent.INITIALIZEevent; the application logic should handle it and programmatically set theAsyncListView.listproperty to thePagedArrayListinstance. For reference I filed a bug in Flex SDK Jira.
Below you can find the source code that resolves the gotchas above. Also the whole Flash Builder project with paged list implementation is available here.
<?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:helpers="com.riaspace.helpers.*" preinitialize="windowedApplication_preinitializeHandler(event)" creationComplete="windowedApplication_creationCompleteHandler(event)"> <fx:Script> <![CDATA[ import mx.collections.errors.ItemPendingError; import mx.events.FlexEvent; protected var conn:SQLConnection; protected const PAGE_SIZE:int = 50; protected function windowedApplication_preinitializeHandler(event:FlexEvent):void { // Creating inmemory database conn = new SQLConnection; conn.open(); // Creating data_tab table var createStmt:SQLStatement = new SQLStatement; createStmt.sqlConnection = conn; createStmt.text = "CREATE TABLE data_tab (value_col TEXT)"; createStmt.execute(); // Inserting 1000 records to the table var insertStmt:SQLStatement = new SQLStatement; insertStmt.sqlConnection = conn; insertStmt.text = "INSERT INTO data_tab VALUES (?)"; for (var i:int = 1; i <= 1000; i++) { insertStmt.clearParameters(); insertStmt.parameters[0] = "value " + i; insertStmt.execute(); } } protected function windowedApplication_creationCompleteHandler(event:FlexEvent):void { // STEP 1 - query rows count var stmt:SQLStatement = new SQLStatement; stmt.sqlConnection = conn; stmt.text = "SELECT count(*) as rowsCount FROM data_tab"; stmt.execute(); var result:SQLResult = stmt.getResult(); // STEP 2 - set PagedArrayList.length equal queried rows count pagedArrayList.length = result.data[0].rowsCount; // STEP 3 - fetch actual data starting from 0 offset (1st row) fetchRows(0); } protected function fetchRows(offset:int):void { // Fetch data rows with specified limit which is our requested page size // and offset passed as parameter var stmt:SQLStatement = new SQLStatement; stmt.sqlConnection = conn; stmt.text = "SELECT * FROM data_tab LIMIT :limit OFFSET :offset"; stmt.parameters[":limit"] = PAGE_SIZE; stmt.parameters[":offset"] = offset; stmt.execute(); var result:SQLResult = stmt.getResult(); if (result && result.data) { for(var i:int = 0; i < result.data.length; i++) { // Setting return row at offset + i position pagedArrayList.setItemAt(result.data[i], offset + i); } } } private function createPendingItemFunctionHandler(index:int, ipe:ItemPendingError):Object { // In case synchronous database mode is used fetchRows function should be called // after return from this function. With asynchronous mode fetchRows function can // be called directly. callLater(fetchRows, [index]); // Returning a message to display return "List items are being fetched from database..."; } protected function pagedArrayList_initializeHandler(event:FlexEvent):void { // NOTICE: this is a workaround for a Flex bug that causes invalidIndex error // in LinearLayoutVector. It all works well when asyncListView.list property // is set after pagedArrayList is initialized and its length property is set. asyncListView.list = pagedArrayList; } ]]> </fx:Script> <fx:Declarations> <helpers:PagedArrayList id="pagedArrayList" initialize="pagedArrayList_initializeHandler(event)" /> </fx:Declarations> <s:List width="100%" height="100%" labelField="value_col"> <s:AsyncListView id="asyncListView" createPendingItemFunction="createPendingItemFunctionHandler" /> </s:List> </s:WindowedApplication>
Adobe Evangelists Blogroll preview
Today I’m officially announcing my new mobile application called Adobe Evangelists Blogroll. This is a simple RSS reader type of application that aggregates blog feeds from my fellow Adobe Evangelists. I’ve developed it with a preview release of Flex Hero SDK and it works on all Android devices that can handle AIR runtime. The app is available in Android Market if you look for “Adobe Evangelists Blogroll“.
What I’m also really excited about is that I managed to repackage it into a bar file and run it on BlackBerry PlayBook emulator without doing even single change to the codebase. In the video below you can see it in action running on different devices and also on PlayBook emulator.
As I already mentioned it was built with preview release of Flex SDK and also the app itself is in beta so it may have some quirks here and there. If you have any suggestions, comments or found some bugs you can contact me through this form.
Few screens of the application (running in landscape & portrait orientation and on playbook):
I just passed Flex 4 Adobe Certified Expert Exam
Today I passed Flex 4 ACE exam. I made a very decent score of 93% with following distribution in the exam sections:
- Creating a User Interface (UI) 85%
- Flex system architecture and design 100%
- Programming Flex applications with ActionScript 100%
- Interacting with data sources and servers 87%
- Using Flex in Adobe AIR 100%
To prepare for the exam I used Attest3, I went through the mock tests 3 or 4 times and at the same time I used Flex 4 help and ActionScript 3 docs as a reference. I encourage anyone to take the exam as it gives you a good overview of your Flex/AIR knowledge.





