The Space For App Developers

Beyond Plain Old HTML Objects

as3viewnavigator 2.0.0 RC1 released!

with 11 comments

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 ViewNavigator for Flex (desktop) projects! At least until ViewNavigator from Flex Hero will not be available for desktop projects ;)
  • ViewNavigator has become a container (based on the Sprite class for AS3 projects and the UIComponent for 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 control ViewNavigator width 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 IView interface called View are provided for both AS3 (based on Sprite) and Flex (based on SkinnableContainer) projects.
  • When performing actions on ViewNavigator (like pop, push, etc.) a ViewNavigatorEvent.VIEW_CHANGING event is dispatched. This event is cancelable so application logic can prevent the view change. Also the event has additional properties like oldView and newView which enable access to the instances of exchanged views.
  • It is now possible to add custom view transitions. This can be done by implementing the IViewTransition interface and setting its implementation instance to the ViewNavigator object’s defaultTransition property or by passing it to the ViewNavigator object’s action functions.
  • View instances managed by ViewNavigator can be destructed when they are no longer on the top of the stack. This can be controlled with a new property in IView interface named destructionPolicy. This property has two possible values auto and never that are also available in the ViewDestructionPolicy enum class. Default IView implementations have this property set to auto.

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):


This movie requires Flash Player 10

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.


This movie requires Flash Player 10

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);
		}
	}
 
...

Written by Piotr Walczyszyn

March 3rd, 2011 at 5:01 pm

Posted in Examples,Releases

Tagged with , ,

11 Responses to 'as3viewnavigator 2.0.0 RC1 released!'

Subscribe to comments with RSS or TrackBack to 'as3viewnavigator 2.0.0 RC1 released!'.

  1. Looks great, but maybe you should disable the pop button or have a reset button in case you’ve popped the last one…Otherwise, looks nice.

    lordB8r

    3 Mar 11 at 5:28 pm

  2. Good point, also you can always refresh the page ;)
    p.

    Piotr Walczyszyn

    3 Mar 11 at 5:36 pm

  3. [...] my previous post about the as3viewnavigator library I briefly mentioned a ViewStack component and its inability to display two views at the [...]

  4. [...] evangelist Piotr Walczyszyn updated his as3viewnavigator project with some significant improvements including supporting it for Flex desktop projects in addition to [...]

  5. Great project!

    What would be best way to do a page system with this?

    Looking at it initially it does not support a simple goTo(viewnum)… Is there reason for this?

    I’ll try and add myself and share back… I have a nice pagination class going just gotta sort out how to switch to specific views (that exist in stack)

    xm

    1 Apr 11 at 10:57 am

  6. Hi Piotr,

    I have used this for a PlayBook app and it is working great! I have one question though.

    - I have a gallery which has multiple pages, when I click an image I push a new view with a larger version of the image.

    -When I ‘pop’ this view of the larger image I am retured to the gallery but to the first page rather than the page the user was previously on.

    Is there a way to maintain the ‘old view’ in it’s previous state rather than creating a new instance of it?

    Any help would be appreciated!

    Scott

    11 Jun 11 at 1:16 am

  7. @Scott this is not possible out-of-the-box but you can also extend the lib and make it works as you want ;)

    Best,
    Piotr

    Piotr Walczyszyn

    13 Jun 11 at 11:19 am

  8. I spent about one hour to workout that slide transition works only when I set width and height of ViewNavigator, so that’s the tip for anyone looking for it! :D .

    I hope I’ll be able to write my custom transition :) .

    Maciek

    23 Jul 11 at 6:05 pm

  9. I just ran across your flex implementation of the ViewNavigator. Thanks for sharing. I’ve got a question about what you think may be the best approach for dealing with delayed transitioning to a view. I have a view that for the most part is a spark list with many thumbnails. When popping back to this view the transition starts but seriously lags while the list loads the images. I’m thinking of extending the lib to allow the loading of the view and adding it to the stage, then when complete start the transition. Any thoughts?

    Pelted

    9 Sep 11 at 5:30 am

  10. @Pelted I think this is good idea to delay the transition. This is actually what is also done in mobile version of ViewNavigator.
    p.

    Piotr Walczyszyn

    9 Sep 11 at 9:07 am

  11. Hi Piotr,

    Great job on this. I made a small modification myself which you may find handy. I added ‘ON_POP’ to ViewDestructionPolicy so views will only get destroyed on pop but not on push. I changed the method ViewNavigatorBase.pop(…) as well to accommodate for this:

    // Destroying hidden view reference
    if (hideView && hideView is IView && ((IView(hideView).destructionPolicy == ViewDestructionPolicy.AUTO) || (IView(hideView).destructionPolicy == ViewDestructionPolicy.ON_POP))
    hideViewReference.destroyInstance();

    This way views are only created on push, but never on pop (for smoother transitions).

    Cheers,

    WP

    WP

    18 Oct 11 at 2:01 pm

Leave a Reply