Flex Maniacs 2007

526 views

Published on

This was a presentation on Custom Formatters, Validators, and Effects for Flex 2.

Published in: Technology, Business
  • Be the first to comment

Flex Maniacs 2007

  1. 1. Custom Formatter, Validator, and Effect Components <ul><li>by Rich Tretola </li></ul>
  2. 2. About Me <ul><li>Rich Applications Technical Lead at Herff Jones Inc. </li></ul><ul><li>Flex Developer for 3+ years </li></ul><ul><li>Lead Author of Professional Flex 2 from Wrox </li></ul><ul><li>Author of Beginning AIR from Wrox (Jan 2008) </li></ul><ul><li>Flex Adobe Community Expert </li></ul><ul><li>Owner and Author of EverythingFlex.com </li></ul>
  3. 3. Scenarios <ul><li>This presentation will cover a variety of scenarios. </li></ul><ul><li>Some of which are feasible and some that just absolutely silly. </li></ul><ul><li>The scenarios will demonstrate how to use the variety of Flex classes that are being covered in this presentation. </li></ul>
  4. 4. Scenario #1 <ul><li>Lets say that you have a manager who wants your applications order numbers which are currently a 7 digit value (1234567) to be formatted in a particular sequence. </li></ul><ul><li>He gives you a sample of 12-34567. </li></ul>
  5. 5. Formatters <ul><li>So, you think I can use a formatter </li></ul><ul><li>Most of us have used some of the following: </li></ul><ul><ul><li>CurrencyFormatter </li></ul></ul><ul><ul><li>DateFormatter </li></ul></ul><ul><ul><li>NumberFormatter </li></ul></ul><ul><ul><li>PhoneFormatter </li></ul></ul><ul><ul><li>ZipCodeFormatter </li></ul></ul>
  6. 6. Example of Number Formatter <ul><li>As a quick refresher, here is an example of a standard NumberFomatter </li></ul>
  7. 7. NumberFormatter import mx.formatters.NumberFormatter; private var myString:String = &quot;1234567&quot; ; private function format():String{ var numFormatter:NumberFormatter = new NumberFormatter(); return numFormatter.format(myString); } Demo
  8. 8. Example of Number Formatter <ul><li>As expected this will not accomplish what we need to do to meet the requested format. </li></ul><ul><li>So what options do we have? </li></ul>
  9. 9. Possible Solutions <ul><li>Well, we could simply parse the value out manually like this: </li></ul>private var myString:String = &quot;1234567&quot; ; private function format():String{ var sub1:String = myString.substr(0,2); var sub2:String = myString.substr(2,5); return sub1 + &quot;-&quot; + sub2; } Demo
  10. 10. Feeling Proud <ul><li>Success! </li></ul><ul><li>OK, so you published your beautiful little order number formatter with the manual parser that you are so proud of. </li></ul>
  11. 11. Scope Creep <ul><li>Success! </li></ul><ul><li>OK, so you published your beautiful little order number formatter with the manual parser that you are so proud of. </li></ul><ul><li>Well guess what, your manager had made a mistake in reading the requirements and says the order number actually needs to be formatted as 12-345-67. </li></ul>
  12. 12. Solutions <ul><li>You could go back and update your manual parsing function or you could use a built in class called the SwitchSymbolFormatter. </li></ul>
  13. 13. Solutions <ul><li>You could go back and update your manual parsing function or you could use a built in class called the SwitchSymbolFormatter. </li></ul><ul><li>And yes, I know that you could do all of this with Regular Expressions also, but that is not the topic of this session. </li></ul>
  14. 14. How Many? <ul><li>How many of you have used the SwitchSymbolFormatter? </li></ul>
  15. 15. What is it? <ul><li>OK, so what is the SwitchSymbolFormatter? </li></ul>
  16. 16. What is it? <ul><li>The SwitchSymbolFormatter class is a very flexible formatter that allows custom format strings as well as custom format characters. </li></ul>
  17. 17. Custom Format String import mx.formatters.SwitchSymbolFormatter; private var myString:String = &quot;1234567&quot; ; private function format():String{ var ssFormatter:SwitchSymbolFormatter = new SwitchSymbolFormatter(); return ssFormatter.formatValue( &quot;##-###-##&quot; ,myString); } Demo
  18. 18. Scope Creep #2 <ul><li>Well, just when you thought you were done, your manager comes to you and says that he again misunderstood the requirements and the order number should actually be formatted as #12-345-67. </li></ul>
  19. 19. Solution? <ul><li>When you look at your current code and realize that you can’t simply add the # sign to the SwitchSymbolFormatter’s format string. </li></ul>
  20. 20. Solution? <ul><li>When you look at your current code and realize that you can’t simply add the # sign to the SwitchSymbolFormatter’s format string. </li></ul><ul><li>If you did use something like this (“###-##-###”) </li></ul>
  21. 21. Solution? <ul><li>When you look at your current code and realize that you can’t simply add the # sign to the SwitchSymbolFormatter’s format string. </li></ul><ul><li>If you did use something like this (“###-##-###”) </li></ul><ul><li>The results would be 123-45-67. </li></ul><ul><li>Note: the last character (8th) in the format string is ignored as the # symbol that you added to the beginning of the format string is now acting like a placeholder for the formatter and not a literal #. </li></ul>
  22. 22. Solution That will work <ul><li>The SwitchSymbolFormatter class has already accounted for this exact scenario by allowing for a custom format character. </li></ul>
  23. 23. Solution That will work <ul><li>The SwitchSymbolFormatter class has already accounted for this exact scenario by allowing for a custom format character. </li></ul><ul><li>The custom format character is passed into the constructor when creating the instance of the SwitchSymbolFormatter. </li></ul>
  24. 24. Custom Format Characters import mx.formatters.SwitchSymbolFormatter; private var myString:String = &quot;1234567&quot; ; private function format():String{ var ssFormatter:SwitchSymbolFormatter = new SwitchSymbolFormatter( &quot;*&quot; ); return ssFormatter.formatValue( &quot;#**-**-***&quot; ,myString); } Demo
  25. 25. Scenario #2 <ul><li>So now you have a request for a formatter that takes whatever the user entered and returned the reverse. </li></ul><ul><li>Rich Tretola should be displayed as aloterT hciR </li></ul>
  26. 26. Solution <ul><li>You could do something like this: </li></ul>private function format(s:String):String{ var returnString:String = &quot;&quot; ; // loop through value and build string in reverse for ( var i:Number=s.length; i>=0; i--){ returnString = returnString + s.charAt(i); } return returnString; }
  27. 27. Solution <ul><li>But a better and reusable solution would be to create a Custom Formatter. </li></ul>
  28. 28. Solution <ul><li>But a better and reusable solution would be to create a Custom Formatter. </li></ul><ul><li>Formatters has been designed to be easily extendable. </li></ul>
  29. 29. How? <ul><li>To write a custom formatter simply extend the mx.formatters.Formatter class. </li></ul>
  30. 30. How? <ul><li>To write a custom formatter simply extend the mx.formatters.Formatter class. </li></ul><ul><li>Then override the format method </li></ul>
  31. 31. ReverseFormatter class package com.everythingflex.flex.formatters { import mx.formatters.Formatter // Custom formatters must extend mx.formatters.Formatter public class ReverseFormatter extends Formatter { public function ReverseFormatter() { super (); } // Custom formatters must override format(). override public function format(formatObj:Object):String{ // ADD OVERRIDE HERE } } }
  32. 32. ReverseFormatter override format method // Custom formatters must override format(). override public function format(formatObj:Object):String{ if (formatObj.length == 0) { // return empty string and set error property if string //has zero length. error= &quot;Can not format an empty String&quot; ; return &quot;&quot; } else { error= null ; var returnString:String = &quot;&quot; ; // loop through value and build string in reverse for ( var i:Number=formatObj.length; i>=0; i--){ returnString = returnString + formatObj.charAt(i); } return returnString; }
  33. 33. Using ReverseFormatter import ReverseFormatter; private var myString:String = &quot;Rich Tretola&quot; ; private function format():String{ var reverseFormatter:ReverseFormatter = new ReverseFormatter(); return reverseFormatter.format(myString); } Demo
  34. 34. Scenario #3 <ul><li>Security is suddenly a concern of management as they are no longer comfortable with employees using a password of “password”. </li></ul><ul><li>He would like to require a password that consists of at least: </li></ul><ul><ul><li>One upper case letter </li></ul></ul><ul><ul><li>One lower case letter </li></ul></ul><ul><ul><li>One number, </li></ul></ul><ul><ul><li>and a length between 6-10 characters </li></ul></ul>
  35. 35. Solutions <ul><li>Well you could try to manually parse out the string of use regular expressions. </li></ul>
  36. 36. Solutions <ul><li>Well you could try to manually parse out the string of use regular expressions. </li></ul><ul><li>But, a better way that allows for code reuse would be to create a custom Validator class </li></ul>
  37. 37. Custom Validator <ul><li>To create a custom Validator class you will simply need to: </li></ul><ul><ul><li>extend the mx.validators.Validator class </li></ul></ul><ul><ul><li>and override the doValidation method </li></ul></ul>
  38. 38. PasswordValidator class package com.everythingflex.flex.validators { import mx.validators.Validator; import mx.validators.ValidationResult; public class PasswordValidator extends Validator { private var results:Array; public function PasswordValidator() { super (); } // Override the doValidation() method. override protected function doValidation(value:Object):Array { // ADD OVERRIDE HERE } } }
  39. 39. Override doValidation // Override the doValidation() method. override protected function doValidation(value:Object):Array { results = []; // Call super's doValidation(). results = super .doValidation(value); // Return if super's doValidation contains // errors (required would be an example). if (results.length > 0){ return results; } // *****Add Custom Validation Here***** return results; }
  40. 40. Now add custom validation // Check for min length if (dataString.length < 6){ results.push( new ValidationResult( true , null , &quot;Short&quot; , &quot;Password must be at least 6 characters.&quot; )); return results; } var dataString:String = String(value); // Check for max length (this can be set in the text component's maxChars property). if (dataString.length > 10){ results.push( new ValidationResult( true , null , &quot;Long&quot; , &quot;Password must be no larger than 10 characters.&quot; )); return results; }
  41. 41. More custom validation // Check for at least 1 upper case letter. if (dataString.search( &quot;[A-Z]&quot; )<0) { results.push( new ValidationResult( true , null , &quot;Upper&quot; , &quot;Passwords must contain at least one upper case letter.&quot; )); return results; } // Check for at least 1 lower case letter. if (dataString.search( &quot;[a-z]&quot; )<0) { results.push( new ValidationResult( true , null , &quot;Lower&quot; , &quot;Passwords must contain at lease one lower case letter.&quot; )); return results; } // Check for at least 1 number. if (dataString.search( &quot;[0-9]&quot; )<0) { results.push( new ValidationResult( true , null , &quot;Number&quot; , &quot;Passwords must contain at least one number.&quot; )); return results; }
  42. 42. Results Demo
  43. 43. Scenario #4 <ul><li>You have been asked to have an object (in this case a button) grow on rollOver and shrink back on rollOut. </li></ul>
  44. 44. Solution <ul><li>You could do something like this: </li></ul>private function rollOver(event:MouseEvent): void { event.target.scaleX=2; event.target.scaleY=2; } private function rollOut(event:MouseEvent): void { event.target.scaleX=1; event.target.scaleY=1; } <mx:Button mouseOver=&quot;rollOver(event)&quot; mouseOut=&quot;rollOut(event)&quot; />
  45. 45. Solution <ul><li>But, a better solution would be to create something that is reusable. </li></ul>
  46. 46. Solution <ul><li>But, a better solution would be to create something that is reusable. </li></ul><ul><li>Create a Custom Effect class </li></ul>
  47. 47. Creating a Custom Effect <ul><li>There are several requirements when creating a custom Effect class. </li></ul><ul><li>First, you will need to extend the mx.effects.Effect class </li></ul><ul><li>You will also need to create a second class extending the mx.effects.EffectInstance class </li></ul>
  48. 48. Effect Class <ul><li>When creating a custom Effect class you must extend the mx.effects.Effect class </li></ul><ul><li>Next you will need to define an instanceClass within the Effect classes constructor </li></ul><ul><li>You will also need to override the getAffectedProperties method </li></ul><ul><li>Lastly, you will need to override the initInstance method and define the instanceClass properties </li></ul>
  49. 49. ScaleEffect Class package com.everythingflex.flex.effects { import mx.effects.Effect; import mx.effects.EffectInstance; import mx.effects.IEffectInstance; public class ScaleEffect extends Effect { // Define scaleTo parameter public var scaleTo:Number; public function ScaleEffect(targetObj:Object = null ){ super (targetObj); instanceClass= ScaleEffectInstance; } // ADD Override getAffectedProperties() // ADD Override initInstance() } }
  50. 50. ScaleEffect Overrides // override getAffectedProperties() and // pass the properties effected override public function getAffectedProperties():Array{ return [ &quot;scaleX,scaleY&quot; ]; } // Override initInstance() override protected function initInstance(inst:IEffectInstance): void { super .initInstance(inst); ScaleEffectInstance(inst).scaleTo = scaleTo; }
  51. 51. EffectInstance Class <ul><li>When creating a custom EffectInstance class you need to extend the mx.effects.EffectInstance class </li></ul><ul><li>You then also may override and of the EffectInstance action methods </li></ul>
  52. 52. ScaleEffectInstance Class package com.everythingflex.flex.effects { import mx.effects.EffectInstance; public class ScaleEffectInstance extends EffectInstance { // Custom Parameter public var scaleTo:Number; public function ScaleEffectInstance(targetObj:Object) { super (targetObj); } // ADD Override play() method. // ADD Override reverse() method. } }
  53. 53. ScaleEffectInstance Overrides // Override play() method. override public function play(): void { super .play(); target.scaleX=scaleTo; target.scaleY=scaleTo; } // Override reverse() method. override public function reverse(): void { target.scaleX=1; target.scaleY=1; }
  54. 54. Results Demo
  55. 55. Scenario #5 <ul><li>Well apparently the scaling button wasn’t exactly what was requested. </li></ul><ul><li>Somehow, it was supposed to be a button that moved across the screen by changing it’s x coordinate. Oh, he also said it needs to bounce at the end of the move. </li></ul>
  56. 56. Solution <ul><li>OK, you could use state management with a Move Effect, but we really want something that is easy to reuse and update. </li></ul><ul><li>So, the answer is a custom Tween Effect. </li></ul>
  57. 57. Custom TweenEffect <ul><li>There are several requirements when creating a custom TweenEffect class. </li></ul><ul><li>First, you will need to extend the mx.effects.TweenEffect class </li></ul><ul><li>You will also need to create a second class extending the mx.effects.TweenEffectInstance class </li></ul>
  58. 58. TweenEffect class <ul><li>When creating a custom TweenEffect class you must extend the mx.effects.TweenEffect class </li></ul><ul><li>Next you will need to define an instanceClass class within the TweenEffect classes constructor </li></ul><ul><li>You will also need to override the getAffectedProperties method </li></ul><ul><li>Lastly, you will need to override the initInstance method </li></ul>
  59. 59. MoveBounceTweenEffect Class package com.everythingflex.flex.effects { import mx.effects.TweenEffect; import mx.effects.EffectInstance; import mx.effects.IEffectInstance; public class MoveBounceTweenEffect extends TweenEffect{ // Define xFrom and xTo parameters public var xFrom:Number; public var xTo:Number; public function MoveBounceTweenEffect(targetObj:Object = null ){ super (targetObj); instanceClass= MoveBounceTweenEffectInstance; } // ADD Override getAffectedProperties() // ADD Override initInstance() }
  60. 60. MoveBounceTweenEffect Overrides // override getAffectedProperties() and // pass the properties effected override public function getAffectedProperties():Array{ return [ &quot;x&quot; ]; } // Override initInstance() override protected function initInstance(inst:IEffectInstance): void { super .initInstance(inst); MoveBounceTweenEffectInstance(inst).xFrom = xFrom; MoveBounceTweenEffectInstance(inst).xTo = xTo; }
  61. 61. TweenEffectInstance <ul><li>When creating a custom TweenEffectInstance class you need to extend the mx.effects.effectClasses.TweenEffectInstance class </li></ul><ul><li>You then also may override and of the TweenEffectInstance action methods </li></ul><ul><li>You will also need to override the getAffectedProperties method </li></ul><ul><li>Lastly, you will need to override the initInstance method and define the instanceClass properties </li></ul>
  62. 62. MoveBounceTweenEffectInstance package { import mx.effects.effectClasses.TweenEffectInstance; import mx.effects.Tween; public class MoveBounceTweenEffectInstance extends TweenEffectInstance { // Move parameters public var xFrom:Number; public var xTo:Number; public function MoveBounceTweenEffectInstance(targetObj:Object){ super (targetObj); } // Override play() method. override public function play(): void { super .play(); // Create the Tween object var tween:Tween = createTween( this , xFrom, xTo, duration); } // Override onTweenUpdate() method. override public function onTweenUpdate(val:Object): void { target.x = val; } // Override onTweenEnd() method. override public function onTweenEnd(val:Object): void { // call super.onTweenEnd(). super .onTweenEnd(val); } } }
  63. 63. Results Demo
  64. 64. Forgot Something <ul><li>We forgot to add the bounce. </li></ul>
  65. 65. Forgot Something <ul><li>We forgot to add the bounce. </li></ul><ul><li>So, lets go back and add an easing function and assign it in a the initInstance function </li></ul>
  66. 66. Easing Function Easing function was borrowed from the Adobe docs private function bounceFunction(t:Number, b:Number, c:Number, d:Number):Number { if ((t /= d) < (1 / 2.75)) { return c * (7.5625 * t * t) + b; } else if (t < (2 / 2.75)) { return c * (7.5625 * (t-=(1.5/2.75)) * t + .75) + b; } else if (t < (2.5 / 2.75)) { return c * (7.5625 * (t-=(2.25/2.75)) * t + .9375) + b; } else { return c * (7.5625 * (t-=(2.625/2.75)) * t + .984375) + b; } } MoveBounceTweenEffectInstance(inst).easingFunction = bounceFunction; Add it to the initInstance method
  67. 67. Results Demo
  68. 68. Benefits of Custom Effect <ul><li>Since we created the animation as a custom effect, it is very simple to add additional objects that use the same effect. </li></ul>Demo
  69. 69. Wrap Up Hopefully, if I have done my job correctly you will now see the benefits of using custom classes for formatters, validators, and effects.
  70. 70. Prizes Question #1 <ul><li>What was the default format character for the SwitchSymbolFormatter? </li></ul>
  71. 71. Prizes Question #1 <ul><li>What was the default format character for the SwitchSymbolFormatter? </li></ul><ul><li># </li></ul>
  72. 72. Prizes Question #2 <ul><li>What method do you need to override when creating a custom formatter? </li></ul>
  73. 73. Prizes Question #2 <ul><li>What method do you need to override when creating a custom formatter? </li></ul><ul><li>format() </li></ul>
  74. 74. Prizes Question #3 <ul><li>What two classes do you need to extend when creating a custom TweenEffect? </li></ul>
  75. 75. Prizes Question #3 <ul><li>What two classes do you need to extend when creating a custom TweenEffect? </li></ul><ul><li>TweenEffect and TweenEffectInstance </li></ul>
  76. 76. Prizes Question #4 <ul><li>What is the name of my daughter as used in the ReverseFormater example? </li></ul>
  77. 77. Prizes Question #4 <ul><li>What is the name of my daughter as used in the ReverseFormater example? </li></ul><ul><li>Skye Tretola :-) </li></ul>
  78. 78. Contact and Downloads Rich Tretola [email_address] or [email_address] Pre sentation and Sour ce available at: http://blog.everythingflex.com

×