Subscribe to RSS
get email updates
home | about | pixDif AIR app | video tutorials
polyGeek.com

place your ad here

Web Premium



Get Qwest High Speed Internet



Adding physics to your gestures

September 1st, 2010 . by polygeek

Adding gesture support for your Flex apps is very easy. But it takes a little extra code to take the experience to the next level by adding a layer of physics to it. The example below is built for touch screens but will work with a mouse just as well. If you want to view it on your mobile phone then try this link: http://polygeek.com/flex/2846_GesturePhysics/_2846_GesturePhysics.html

view source

The code in this example is an extension of work done by James Ward in his post Flex 4 List Scrolling on Android with Flash Player 10.1

How it works
Start by listening for applicationComplete and adding listeners for the following gestures: TOUCH_BEGIN, TOUCH_MOVIE, TOUCH_END.

public function appInit():void {
	_movieService = new MovieService_2846();

	_tic = new Timer( 33 );
	_tic.addEventListener( TimerEvent.TIMER, onTic );

	if ( Multitouch.supportsTouchEvents ) {
		// supports touch events
		Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
		FlexGlobals.topLevelApplication.stage.addEventListener(
			TouchEvent.TOUCH_BEGIN, onTouchBegin );
	} else {
		// Does NOT support touch events
		FlexGlobals.topLevelApplication.stage.addEventListener(
			MouseEvent.MOUSE_DOWN, onMouseDown );
		FlexGlobals.topLevelApplication.stage.addEventListener(
			MouseEvent.MOUSE_UP, onMouseUp );
	}
}

Here are the event handlers. The _isTouching Boolean prevents the scrolling from behaving oddly when the user tries to scroll past the top or bottom of the list.

private function onTouchBegin( e:TouchEvent ):void {
	// A touch event has begun so add listeners for TOUCH_MOVE and TOUCH_END.
	FlexGlobals.topLevelApplication.stage.addEventListener(
		TouchEvent.TOUCH_MOVE, onTouchMove );
	FlexGlobals.topLevelApplication.stage.addEventListener(
		TouchEvent.TOUCH_END, onTouchEnd );

	// We can stop listening for TOUCH_BEGIN until this current TOUCH_BEGIN ends.
	FlexGlobals.topLevelApplication.stage.removeEventListener(
		TouchEvent.TOUCH_BEGIN, onTouchBegin );

	// _isTouching prevents the scrolling from behaving oddly when
	// the user tries to scroll past the min/max.
	_isTouching = true;
	_prevY = e.stageY;
	_tic.stop(); // Just to make sure the Timer isn't running.
}

I’m offloading the code to determine how to move the list to a separate function so that it can be used by both touch and mouse events.

private function onTouchMove( e:TouchEvent ):void {
	moving( e.stageY );
}

moving();
tempDelta measures how far the user has moved their finger since the last time the onTouchMove event fired. I’m multipling by a small factor, 1.2 in this example, to help the user scroll. This will make the list scroll just a little faster than the user swipes. This is also beneficial in the case that you are dealing with a list of Buttons. If in the process of swiping the user presses and releases on the same button it may register a button press event – which you probably don’t want. If the list moves faster than the swipe then the chances of that happening are reduced.

Instead of setting _deltaY directly I’m going through an intermediate – _tempDelta. That is to make sure we don’t set _deltaY to 0. Sometimes that happens with the touch events registering twice just as the user finishes a swipe. It also has the added benefit of letting the user swipe once and then just place their finger over the nav to keep the nav scrolling automatically.

private function moving( stageY:int ):void {
	// Multiply by a small factor - 1.2 in this example - to help the user scroll.
	// This will make the app scroll just a little faster than they swipe.
	var tempDelta:Number = Math.round( ( _prevY - stageY ) ) * 1.2;

	// The 'tempDelta' makes sure that we don't set _deltaY to 0. Sometimes that
	// happens with the touch events registering twice just as the user finishes
	// a swipe. It also has the added benefit of letting the user swipe once and then
	// just place their finger over the nav to keep the nav scrolling automatically.
	_deltaY = ( tempDelta != 0 ) ? tempDelta : _deltaY;

	// Under some circumstances just barely touching, or tapping with two fingers,
	// can create a very large _deltaY. This makes sure that _deltaY doesn't exceed
	// a max value of ± 20 - which is arbitrary.
	_deltaY = ( _deltaY > 20 ) ? 20 : _deltaY;
	_deltaY = ( _deltaY < -20 ) ? -20 : _deltaY;

	calculateScrollPosition();
	_prevY = stageY;
}

Now that the user has ended a swipe start the timer so we can let the nav coast to a stop.

private function onTouchEnd( e:TouchEvent ):void {
	// The touch event has ended so now start listening for a TOUCH_BEGIN event again.
	FlexGlobals.topLevelApplication.stage.addEventListener(
		TouchEvent.TOUCH_BEGIN, onTouchBegin );

	// We don't need to listen for TOUCH_MOVE or TOUCH_END until a touch event begins again.
	FlexGlobals.topLevelApplication.stage.removeEventListener(
		TouchEvent.TOUCH_MOVE, onTouchMove );
	FlexGlobals.topLevelApplication.stage.removeEventListener(
		TouchEvent.TOUCH_END, onTouchEnd );
	_isTouching = false;

	// Now that the user has ended a swipe start the timer so we can let the nav
	// coast to a stop.
	_tic.start();
}

The actual moving is done by the calculateScrollPosition() function which is called when the user is in the process of swiping and when the Timer ( _tic ) is running.

You can see that the if-statement executes when the list has reached the top. I’m using the last value of _deltaY to adjust the animation that moves the entire list down and then bounces it back into position. If _deltaY is large then the entire list will bounce a lot. If it’s just barely moving then the list will move just a little bit. Same goes for the else-statement when the list has reached the bottom.

private function calculateScrollPosition():void {
	var desiredScrollPosition:Number = dataGroup.verticalScrollPosition + _deltaY;

	if ( desiredScrollPosition < 0 && !_isTouching ) {
		// Stop coasting the nav.
		desiredScrollPosition = 0;
		_tic.stop();
		// Use the last value of _deltaY to adjust the bounce. If _deltaY is
		// large then the nav will bounce a lot. If it's just barely moving
		// then the nav will move just a little bit.
		bounceBottomStart.yBy = Math.abs( _deltaY ) * 2;
		bounceBottom.play();
	} else if ( desiredScrollPosition > dataGroup.contentHeight - dataGroup.height
			&& !_isTouching ) {
		desiredScrollPosition = dataGroup.contentHeight;
		_tic.stop();
		// See comment above.
		bounceTopStart.yBy = -Math.abs( _deltaY ) * 2;
		bounceTop.play();
	}
	dataGroup.verticalScrollPosition = desiredScrollPosition;
}

Lastly we’ll need the onTic handler which gives the list its coasting to a stop behavior. Multiply _deltaY by a factor smaller than 1 so that the nav will slow down over time. The closer the value is to 0 the faster the nav will slow down. Likewise the closer the factor is to 1 the longer it will take. Don’t make the factor larger than 1. That would be bad.

private function onTic( e:TimerEvent ):void {
	// Multiply by a factor smaller than 1 so that the nav will slow down over time.
	// The closer the value is to 0 the faster the nav will slow down. Likewise the
	// closer the factor is to 1 the longer it will take. Don't make the factor larger
	// than 1. That would be bad.
	_deltaY *= 0.9;
	// 0.3 is an arbitrary threshold to stop the coasting.
	if( Math.abs( _deltaY ) < 0.3 ) {
		_tic.stop();
	}
	calculateScrollPosition();
}

You may notice the scrollBounceTop.play() and scrollBounceBottom.play(). Those are animations declared in the <fx:Declarations> section. That’s what bounces the list up or down when it scrolls to either the beginning or end.

<fx:Declarations>
	<!--Easing-->
	<s:Bounce id="bounce" />
	<s:Power id="easeInOut" easeInFraction=".5" exponent="2" />

	<!--Bounce DataGroup: top-->
	<s:Sequence id="bounceBottom">
		<s:Move
			id="bounceBottomStart"
			target="{ scroller }"
			duration="400"
			easer="{ easeInOut }" />
		<s:Move
			id="bounceBottomEnd"
			target="{ scroller }"
			yTo="50" duration="400"
			easer="{ bounce }" />
	</s:Sequence>

	<!--Bounce DataGroup buttom-->
	<s:Sequence id="bounceTop">
		<s:Move
			id="bounceTopStart"
			target="{ scroller }"
			duration="400"
			easer="{ easeInOut }"/>
		<s:Move
			target="{ scroller }"
			yTo="50" duration="400"
			easer="{ bounce }"/>
	</s:Sequence>
</fx:Declarations>

thats it

If something here has proved valuable to you then feel free to drop a couple of bucks in the tip-jar.

Post to Twitter Post to Delicious Post to Facebook Post to Reddit Post to StumbleUpon


similar posts

Adding Flex 4 states at runtime

August 31st, 2010 . by polygeek

If I’ve said it once I’ve said it a 1000 times, “Flex 4 states ROCK!” One minor grip I did have was that it wasn’t possible to add states at runtime. I tried and tried until I found a statement buried in the docs that indicated that adding runtime states wasn’t possible but would be added in a future update to the framework. ( see note at the bottom ) I guess that finally got rolled out because I ran into this post – Creating Flex View States in ActionScript – the other day showing an example of how to add states at runtime.

I find the example provided by the docs team a bit unwieldy – what’s new? Below is an example and the code for, what I think, is a more intuitive way to do the same thing. The ButtonBar changes the states. The first two states – default and big - are added at compile time. The third state Bang-a-Gong is added at runtime.

view source

The init() file is called on creationComplete. Just to be thorough I also added a transition for this state.

private function init():void {
	// Create a new state and give it a name.
	var stateBang:State = new State();
	stateBang.name = 'Bang-a-Gong';

	// Set the overrides with an array of AddChild, AddItems,
	// RemoveChild, SetEventHandler, SetProperty, and SetStyle
	stateBang.overrides =
		[ new SetProperty( btn, "label", "Bang-a-Gong" ),
		  new SetProperty( btn, "height", "150" ),
		  new SetProperty( btn, "width", "300" ),
		  new SetStyle( btn, "fontSize", "22" ),
		  new SetStyle( btn, "fontWeight", "bold" ),
		  new SetStyle( btn, "color", "#FF0000" ) ];

	// Add our new state to the available states of this component.
	this.states.push( stateBang );

	// Just for kicks lets add a transition for this state.
	var transition:Transition = new Transition();
	transition.toState = 'Bang-a-Gong';

	// Create a new transition effect.
	var resize:Resize = new Resize( btn );

	// Create an composite effect, either: Sequence or Parallel.
	var sequence:Sequence = new Sequence();

	// Add our resize effect.
	sequence.addChild( resize );

	// now add our composition effect to the transition we created.
	transition.effect = sequence;

	// Push our new transition into the transitions array for this component.
	this.transitions.push( transition );
}

I’ve only run across one situation where I needed to add states at runtime and now I can’t remember exactly what it was. If you have a use-case I’d appreciate it if you commented below.

Note: I believe that adding states like this at runtime may have been possible all along. I just reread the Adobe Doc: Enhanced States Syntax where I originally discovered that runtime states weren’t possible:

Enhanced Runtime API – As a fit and finish task, it would be prudent to update the runtime states API to follow closer to the way the new syntax works. e.g. A helper would be provided that would allow a developer to setPropertyForState(object, property, state) for instance. Or specifically set the include or exclude list for a given component instance. Essentially an API divorced from the notion of the current runtime States and Overrides model. When the work is done on this feature, a mini-spec will be circulated.

I mistook that to mean that it couldn’t be done until they added the setPropertyForState( object, property, state ) to the API. But that’s just a convenient way to do what I did above.

If something here has proved valuable to you then feel free to drop a couple of bucks in the tip-jar.

Post to Twitter Post to Delicious Post to Facebook Post to Reddit Post to StumbleUpon


similar posts

Grouping data in a DataGroup ( nested DataGroups )

August 24th, 2010 . by polygeek

You know what’s better than DataGroups? Nested DataGroups, that’s what! Previously I showed how to add data to a DataGroup that would act to logically break up the content. Here I’m doing essentially the same thing except with nested DataGroups.

The outer DataGroup has a dataProvider that is an ArrayCollection of ArrayCollections. The inner ArrayCollection contains movieVOs grouped either by the month that the movie was released or by the first character of the movie title.

view source

With nested DataGroups you’ll need two ItemRenderers. The outer ItemRenderer will itself contain a DataGroup that will have an ItemRenderer that just displays the movie title. The outer ItemRenderer is where the labels and rectangle are created. To alternate the state back and forth between left and right I used something like this:

this.currentState = ( data.firstCharacter.charCodeAt( 0 ) % 2 == 0 ) ? 'left' : 'right';

Since the charCodes are sequential the state will alternate back and forth except in the case where a letter might be missing in the sequence of first characters. You can see that happen between P and R. There are no movies that came out last year beginning with the letter Q. If you wanted to make sure that the bars alternated from left to right no matter what then you’d have to created an external counter – which would be easy enough.

The thing that took the longest was working around grouping the movie titles that begin with a number: 2012 and 9. I worked through a number of ways that didn’t quite work until I finally hit upon something that seems to work.

If something here has proved valuable to you then feel free to drop a couple of bucks in the tip-jar.

Post to Twitter Post to Delicious Post to Facebook Post to Reddit Post to StumbleUpon


similar posts

Using a DataGroup’s itemRendererFunction to group content

August 24th, 2010 . by polygeek

The Flex DataGroup is not limited to using just one ItemRenderer at a time. You can use as many different ItemRenderers as you would like. To do so you use the itemRendererFunction to determine which ItemRenderer to use for a specific type of data.

On the next version of RunPee.com – for mobile – I’m using a DataGroup as the movie navigation. To make it easier for the user to find movies I would like to break of the list into groups of movies – either by date or alphabetically.  Here is the prototype that I built:

view source

All I’m doing is sorting through the list of MovieVOs and inserting either a WeekVO or AlphaVO depending on how the data is sorted.

Here is the itemRendererFunction:

private function onItemRenderer( item:Object ):IFactory {
	var clazz:Class;
	switch( item.type ) {
		case MovieVO.TYPE :
			clazz = renderers.MovieRenderer;
			break;
		case WeekVO.TYPE :
			clazz = renderers.MovieDateRenderer;
			break;
		case AlphaVO.TYPE :
			clazz = renderers.MovieAlphaRenderer;
			break;
		}
	return new ClassFactory( clazz );
}

You probably don’t want to make the dividers selectable – like I have here. If so then check out Tink’s post on ExcludeSelectionList

Check out the Flex 4 Cookbook (Oreilly Cookbooks) pg. 39 for more good stuff on DataGroups and ItemRenderers.

If something here has proved valuable to you then feel free to drop a couple of bucks in the tip-jar.

Post to Twitter Post to Delicious Post to Facebook Post to Reddit Post to StumbleUpon


similar posts

Geeksual

August 9th, 2010 . by polygeek

geek•su•al [ geek-shoo-uhl ] – adjective

  1. pertaining to, inclined to, or preoccupied with the gratification of geekish sensibilities.

Usage:
Opening a box with some electronic device inside is a geeksual experience that should be done slowly and deliberately to let the anticipation build until the ultimate moment that you hold your new toy in your hands.

I’ll never forget the experience of seeing a movie trailer back in 2008. With nothing but a black screen and a single, constant, musical tone I knew instantly it was a preview to the next Star Trek movie. It was one of the most geeksual moments I’ve ever had.

Origin:
Coined by polyGeek on August 09, 2010 in a conversation with @proudgamer. In reference to receiving a new HP multi-touch monitor.

Please share your most geeksual experiences in the comments.

If something here has proved valuable to you then feel free to drop a couple of bucks in the tip-jar.

Post to Twitter Post to Delicious Post to Facebook Post to Reddit Post to StumbleUpon


similar posts

« Previous Entries    



polyGeek.com

© Copyright 2008 polyGeek.com / Dan Florio, All Rights Reserved Except Where Explicitly Stated
Web Developement Blogs - Blog Catalog Blog Directory
M2 Websites
Local Directory for Los Angeles, CA

Better Tag Cloud