2 Replies Latest reply on Mar 29, 2010 10:07 AM by flairjax

    Sortable list issues (icon rendering issues) FB4

    flairjax Level 1

      So I have a sortable list component that was working fine in FB4 beta 2, but now in the FB4 premium version, when I click to sort my list based on name or other field the icons scale by about 500% and flash on screen for about .5 seconds and then the once the sorting is finished they go back to the correct position and size.

       

      Here is the code:

       

      HERE IS WHERE ITS USED:

      <components:CollapsiblePanel id="collapsePanel"
               skinClass="assets.style.skins.panel.CustomPanelSkin"
               maxWidth="250" right="-25" top="{navControlBar.height - 1}"
               title="Quick Find:" bottom="-1"
                >
              <components:layout>
                  <s:VerticalLayout paddingLeft="0" paddingRight="0" paddingTop="0" paddingBottom="0" />
              </components:layout>
              <components:CollapsibleSortableList id="deviceList"
                      creationComplete="setupDeviceListListeners()"
                      skinClass="assets.style.skins.list.CollapsibleSortableListSkin"
                      change="deviceList_selectionHandler(event)"
                      caretChange="deviceList_selectionHandler(event)"
                      height="100%"
                      width="100%"
                      borderVisible="false"
                       />
          </components:CollapsiblePanel>

       

       

       

      CUSTOM CLASS SORTABLE LIST COMP:

      package com.spiceworks.networkmap.view.components
      {
          import assets.style.skins.buttonbar.PlainButtonBarSkin;
         
          import flash.events.MouseEvent;
         
          import mx.collections.ICollectionView;
          import mx.collections.Sort;
          import mx.collections.SortField;
          import mx.events.StateChangeEvent;
          import mx.utils.ObjectUtil;
         
          import spark.components.ButtonBar;
          import spark.components.List;
         
          [SkinState("halfOpened")];
          [SkinState("fullyOpened")];
          [SkinState("collapsed")];
          public class CollapsibleSortableList extends List
          {
              protected var _collapsed:Boolean = false;
              protected var _halfOpened:Boolean = true;
              protected var _fullyOpened:Boolean = false;
             
              //Declare the additional SkinStates
              [SkinPart(required="false")]
              public var sortButtonBar:ButtonBar;
             
              /*[SkinPart(required="true")]
              public var header:Button;*/
             
              private const SORT_ASCENDING:int = 0;
             
              private const SORT_DESCENDING:int = 1;
             
              private var _sorting:int = SORT_DESCENDING;
             
              private var _sort:Sort;
             
              private var _sortField:String = 'name';
             
              private var _dataSortField:SortField;
              private var _numericDataSort:Sort;
              private var _alphaSort:Sort;
              private var _dp:ICollectionView;
             
              public function CollapsibleSortableList()
              {
                  super();
              }
             
             
              //Add Event-Listeners to the textview for FocusEvent
              override protected function partAdded(partName:String, instance:Object):void {
                  super.partAdded(partName, instance);
                  if (instance == sortButtonBar) {
                      trace ("Adding sort button");
                      ButtonBar(instance).setStyle( 'skinClass', assets.style.skins.buttonbar.PlainButtonBarSkin );
                      ButtonBar(instance).addEventListener( MouseEvent.CLICK, sortButtonBar_changeHandler);
                  }
              }
             
              //Clean up Event-Listeners and stuff...
              override protected function partRemoved(partName:String, instance:Object):void {
                  super.partRemoved(partName, instance);
                  if (instance == sortButtonBar) {
                      trace ("Removing sort button");
                      ButtonBar(instance).removeEventListener(MouseEvent.CLICK, sortButtonBar_changeHandler);
                  }
              }
             
              private function convertIPToInteger( val:Object ) : Number
              {
                  var num:Number = 0;
                  var pattern:RegExp = /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
                 
                  if(val && val.ip != null){
                      var str:String = val.ip;
                      trace(pattern.exec(str));
                      var o:* = pattern.exec(str);
                  }
                  if( o == null ) { return num };
                  var p1:Number = parseInt(o[1]) * 16777216;
                  var p2:Number = parseInt(o[2]) * 65536;
                  var p3:Number = parseInt(o[3]) * 256;
                  var p4:Number = parseInt(o[4]) * 1;
                  num = p1 + p2 + p3 + p4;
                 
                  return num;
              }
             
              private function convertNetworkToInteger( val:Object ) : Number
              {
                  var num:Number = 0;
                  var pattern:RegExp = /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\/([0-9]+)/;
                 
                  if(val && val.network != null){
                      var str:String = val.cloud;
                      trace(pattern.exec(str));
                      var o:* = pattern.exec(str);
                  }
                  if( o == null ) { return num };
                  var p1:Number = parseInt(o[1]) * 4294967296;
                  var p2:Number = parseInt(o[2]) * 16777216;
                  var p3:Number = parseInt(o[3]) * 65536;
                  var p4:Number = parseInt(o[4]) * 256;
                  var p5:Number = parseInt(0[5]) * 1
                  num = p1 + p2 + p3 + p4 + p5;
                 
                  return num;
              }
             
              private function ip_compareFunc( itemA:Object, itemB:Object ) : int
              {
                  var valueA:Number = convertIPToInteger( itemA );
                  var valueB:Number = convertIPToInteger( itemB );
                  return ObjectUtil.numericCompare( valueA, valueB );
              }
             
              private function network_compareFunc( itemA:Object, itemB:Object ) : int
              {
                  var valueA:Number = convertNetworkToInteger( itemA );
                  var valueB:Number = convertNetworkToInteger( itemB );
                  if( itemA == itemB ) {
                      if( itemA.type == 'cloud' ){
                          return 1;
                      }else if( itemB.type == 'cloud' ) {
                          return -1;
                      }
                  }
                  return ObjectUtil.numericCompare( valueA, valueB );
              }

       

             
              protected function sortButtonBar_changeHandler(event:*):void
              {
                  var str:String = event.target.label as String;
                  str = str.toLowerCase();
                  this._sortField = str;
                  //sortList();
                 
                  /* Create the SortField object for the correct field in the ArrayCollection object  */
                  _dataSortField = new SortField();
                  _dataSortField.name = _sortField;
                 
                  if( str == 'name' ){
                      doAlphaSort();
                  }else if( str == 'ip' ){
                      _dataSortField.compareFunction = ip_compareFunc;
                      doSpecialSort();
                  }else{
                      _dataSortField.compareFunction = network_compareFunc;
                      doSpecialSort();
                  }
              }
             
              private function doAlphaSort() : void
              {
                  _dp = this.dataProvider as ICollectionView;
                 
                  /* Create the Sort object and add the SortField object created earlier to the array of fields to sort on. */
                  _alphaSort = new Sort();
                  _alphaSort.fields = [_dataSortField];
                 
                  /* Set the ArrayCollection object's sort property to our custom sort, and refresh the ArrayCollection. */
                  if (_dp != null)
                  {
                      if (this._sorting == SORT_ASCENDING)
                      {
                          this._alphaSort.reverse();
                          this._sorting = SORT_DESCENDING;
                      }
                      else
                      {
                          this._sorting = SORT_ASCENDING;
                      }
                     
                      _dp.sort = this._alphaSort;
                      _dp.refresh();
                  }
              }
             
              private function doNumericSort() : void
              {
                  _dp = this.dataProvider as ICollectionView;
                  _dataSortField.numeric = true;
                 
                  /* Create the Sort object and add the SortField object created earlier to the array of fields to sort on. */
                  _numericDataSort = new Sort();
                  _numericDataSort.fields = [_dataSortField];
                 
                  /* Set the ArrayCollection object's sort property to our custom sort, and refresh the ArrayCollection. */
                  if (_dp != null)
                  {
                      if (this._sorting == SORT_ASCENDING)
                      {
                          this._numericDataSort.reverse();
                          this._sorting = SORT_DESCENDING;
                      }
                      else
                      {
                          this._sorting = SORT_ASCENDING;
                      }
                     
                      _dp.sort = this._numericDataSort;
                      _dp.refresh();
                  }
              }
             
              private function doSpecialSort() : void
              {
                  _dp = this.dataProvider as ICollectionView;
                 
                  /* Create the Sort object and add the SortField object created earlier to the array of fields to sort on. */
                  _numericDataSort = new Sort();
                  _numericDataSort.fields = [_dataSortField];
                 
                  /* Set the ArrayCollection object's sort property to our custom sort, and refresh the ArrayCollection. */
                  if (_dp != null)
                  {
                      if (this._sorting == SORT_ASCENDING)
                      {
                          this._numericDataSort.reverse();
                          this._sorting = SORT_DESCENDING;
                      }
                      else
                      {
                          this._sorting = SORT_ASCENDING;
                      }
                     
                      _dp.sort = this._numericDataSort;
                      _dp.refresh();
                  }
              }
             
             
              private function sortList():void
              {
                  var dp:ICollectionView = this.dataProvider as ICollectionView;
                  this._sort = new Sort();
                  this._sort.fields = [new SortField(this._sortField)];
                 
                  if (dp != null)
                  {
                      if (this._sorting == SORT_ASCENDING)
                      {
                          this._sort.reverse();
                          this._sorting = SORT_DESCENDING;
                      }
                      else
                      {
                          this._sorting = SORT_ASCENDING;
                      }
                     
                      dp.sort = this._sort;
                      dp.refresh();
                  }
              }
             
              //Gets called after invalidateSkinState() by Flex
              override protected function getCurrentSkinState():String {
                  if (_collapsed) {
                      this.dispatchEvent(new StateChangeEvent( StateChangeEvent.CURRENT_STATE_CHANGING, false, false, null, 'collapsed' ) );
                      return "collapsed";
                  }else if( _halfOpened ){
                      this.dispatchEvent(new StateChangeEvent( StateChangeEvent.CURRENT_STATE_CHANGING, false, false, null, 'halfOpened' ) );
                      return "halfOpened";
                  }else if( _fullyOpened ) {
                      this.dispatchEvent(new StateChangeEvent( StateChangeEvent.CURRENT_STATE_CHANGING, false, false, null, 'fullyOpened' ) );
                      return "fullyOpened";
                  }else{
                      return super.getCurrentSkinState();
                  }
              }


          }
      }

       

       

       

       

      CUSTOM SKIN:

      <?xml version="1.0" encoding="utf-8"?>
      <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
                   xmlns:s="library://ns.adobe.com/flex/spark"
                   xmlns:mx="library://ns.adobe.com/flex/mx"
                   >
         
          <fx:Metadata>
              [HostComponent("assets.style.skins.list.CollapsibleSortableListSkin")]
          </fx:Metadata>
         
          <s:states>
              <s:State name="collapsed" />
              <s:State name="halfOpened" />
              <s:State name="fullyOpened" />
              <s:State name="normal" />
              <s:State name="over"/>
          </s:states>
         
          <!-- background -->
          <s:Rect top="20" right="0" bottom="0" left="0">
              <s:stroke>
                  <s:SolidColorStroke color="0xffffffff" weight="1" />
              </s:stroke>
              <s:fill>
                  <s:SolidColor color="0xffffff" color.over="0xf8f8f8" />
              </s:fill>
          </s:Rect>
         
          <!-- scroller -->
          <s:Scroller id="scroller"
                      left="0"
                      top="19"
                      right="0"
                      bottom="0"
                      horizontalScrollPolicy="off"
                      minViewportInset="1"
                      focusEnabled="false">
             
              <!-- container for data-->
              <s:DataGroup id="dataGroup">
                  <s:layout>
                      <s:VerticalLayout gap="0" horizontalAlign="contentJustify" />
                  </s:layout>
              </s:DataGroup>
             
          </s:Scroller>
         
          <s:ButtonBar id="sortButtonBar"
                       styleName="sortableButtonBar"
                       left="0" right="0"
                       height="20"
                       useHandCursor="true" buttonMode="true">
              <s:dataProvider>
                  <s:ArrayList source="[Name,IP,Network]" />
              </s:dataProvider>
          </s:ButtonBar>

       

         
      </s:SparkSkin>

        • 1. Re: Sortable list issues (icon rendering issues) FB4
          flairjax Level 1

          Here is my itemRenderer:

           

          <?xml version="1.0" encoding="utf-8"?>
          <s:ItemRenderer width="100%"
                          xmlns:fx="http://ns.adobe.com/mxml/2009"
                          xmlns:s="library://ns.adobe.com/flex/spark"
                          xmlns:mx="library://ns.adobe.com/flex/mx"
                          useHandCursor="true" buttonMode="true">
             
              <fx:Script>
                  <![CDATA[
                      import com.spiceworks.networkmap.utils.Images;
                     
                      import mx.controls.Image;
                      import mx.events.FlexEvent;
                     
                      import spark.filters.GlowFilter;
                    
                      [Bindable]
                      private var deviceEntry:Object
                         
                      private var gf:GlowFilter;
                     
                      /**
                       *  callback function for delete icon click
                       */
                      public var deleteHandlerFunction:Function;
                     
                      /**
                       *  override set data to set BlogEntryVO
                       */
                      override public function set data(value:Object):void {
                          super.data = value;
                          deviceEntry = value;
                         
                          // setup colors and alphas
                          if( deviceEntry && !deviceEntry.intree ) {
                              backing.color = 0x6699cc;
                              icon.filters = [];
                              this.dispatchEvent( new FlexEvent(FlexEvent.DATA_CHANGE, true) ) ;
                          }else if( deviceEntry && deviceEntry.intree == 'in'){
                              backing.color = 0xFF652F;
                              gf = new GlowFilter(0xFF652F, .75, 7, 7, 4);
                              icon.filters = [gf];
                              this.dispatchEvent( new FlexEvent(FlexEvent.DATA_CHANGE, true) ) ;
                          }
                      }
                     
                      /**
                       *  override set data to set BlogEntryVO
                       */
                      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                          super.updateDisplayList(unscaledWidth,unscaledHeight);
                         
                          if (device_btn) {
                              device_btn.text = deviceEntry.name;
                              if(ip_lbl) { ip_lbl.text = deviceEntry.ip };
                              this.icon.source = Images.resource_small(deviceEntry.type);
                             
                             
                              if( ip_lbl && ip_lbl.text == '' || ip_lbl.text == null ) {
                                  ip_lbl.text = 'ip not found';
                              }
                             
                              //Remove ip_Lbl if it isn't an ip addres
                              var pattern:RegExp = /([0-9]+)\./;
                              if( !pattern.test( ip_lbl.text ) ){
                                  ip_lbl.text = 'not found';
                              }
                             
                              //iconHolder.removeAllElements();
                              for each (var s:String in deviceEntry.type) {
                                  var icon:* = Images.resource_small(deviceEntry.type);
                                  if (icon) {
                                      device_btn.setStyle('icon', icon);
                                      //device_btn.addElement(icon);
                                      //iconHolder.addElement(icon);
                                  }
                              }
                          }               
                      }
                     
                      /**
                       *  handler for trash icon click, callback with blogEntry VO passed
                       */
                      private function device_btn_clickHandler(event:MouseEvent):void {
                          //deleteHandlerFunction(deviceEntry);
                      }
                      private function stripDash( str:String ) : String
                      {
                          var myPattern:RegExp = new RegExp( "-", "g" ); 
                          var s: String = str.replace(myPattern, " ");
                          return s;
                      }
                     
                  ]]>
              </fx:Script>
             
              <s:states>
                  <s:State name="normal" />
                  <s:State name="hovered" stateGroups="[hoveredStates]" />
                  <s:State name="selected" stateGroups="[selectedStates]" />
                  <s:State name="normalAndShowsCaret" />
                  <s:State name="hoveredAndShowsCaret" stateGroups="[hoveredStates]" />
                  <s:State name="selectedAndShowsCaret" stateGroups="[selectedStates]" />
              </s:states>
             
              <s:Rect left="0" bottom="1" right="1" height="2">
                  <s:fill>
                      <s:SolidColor color="0x000000" alpha=".2"/>
                  </s:fill>
              </s:Rect>
             
              <s:Rect width="100%" height="100%">
                  <s:fill>
                      <s:SolidColor id="backing" color="0x6699cc" alpha="0" alpha.hoveredStates=".1" alpha.selectedStates=".25" />
                  </s:fill>
              </s:Rect>
              <s:Group height="45">
                  <s:HGroup id="nameHolderGroup" left="5" right="10" gap="4" top="3">
                      <!--<mx:Image id="icon" source="{Images.resource(deviceEntry.type)}" />-->
                      <s:BitmapImage id="icon"
                                     source="{Images.resource(deviceEntry.type)}"
                                     smooth="true"
                                     left="0" right="0"
                                     top="0" bottom="0">
                      </s:BitmapImage>
                     
                      <s:Group top="3">
                          <mx:Label id="device_btn"
                                    buttonMode="true"
                                    toolTip="{device_btn.text}"
                                    maxWidth="100"
                                    textAlign="left"
                                    fontSize="11"
                                    top="0"
                                    fontWeight="bold"
                                    rollOver="{event.target.setStyle('textDecoration', 'underline') }"
                                    rollOut="{event.target.setStyle('textDecoration', 'none')}"
                                    click="device_btn_clickHandler(event)"
                                    />
                      </s:Group>
                  </s:HGroup>
                      <s:VGroup gap="3" left="10" top="{nameHolderGroup.x + nameHolderGroup.height }" bottom="5">
                          <s:HGroup  left="9" right="10" gap="4">
                              <mx:Image source="" />
                              <s:Label  text="IP:"
                                        styleName="myriad"
                                        maxDisplayedLines="1"
                                        fontSize="11"
                                        paddingTop="3"
                                        textAlign="justify"
                                        color="#121212"
                                        color.selectedStates="#121212"/>
                              <s:Label id="ip_lbl"
                                       styleName="myriad"
                                       maxDisplayedLines="1"
                                       fontSize="11"
                                       maxWidth="120"
                                       paddingTop="3"
                                       textAlign="justify"
                                       color="#4e5265"
                                       color.selectedStates="#121212"/>
                          </s:HGroup>
                      </s:VGroup>
              </s:Group>
             
          </s:ItemRenderer>

          • 2. Re: Sortable list issues (icon rendering issues) FB4
            flairjax Level 1

            Got it. I have a call to Images.resource which is function that in a little helper I have that brings back regular size images.  I need to use my Image.resourcesmall function call to return my small images. So what what was happening was it was bringing back the large images during the sort and are having to scale them.

             

            Stupid mistake.  But hey now I fixed it and don't have the overhead of scaling the images....two birds with one....

             

            Nothing to see here move along.

             

            J