4 Replies Latest reply on Oct 26, 2010 2:52 PM by leecoltrane

    Custom View States in an itemRenderer


      Hi all,


      ItemRenderers do not properly use custom states.

      Here is the code for my itemRenderer with a custom state - 'testState'



      <?xml version="1.0" encoding="utf-8"?>
      <s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                     override protected function getCurrentRendererState():String
                          var t = super.getCurrentRendererState();
                          if (hasState("testState") && data == 'testvalue') {
                               return "testState";
                          return t;
                <s:State name="normal" />
                <s:State name="hovered" />
                <s:State name="testState" />
           <s:Rect width="100%" height="100%" includeIn="testState" >
                     <s:SolidColor color="0x000000"/>
           <s:Label id='lal' text="{data}" color.testState="0xAA0000" color.hovered="0xCCCCCC" width="100%" height="100%" verticalAlign="middle" textAlign="center">
      The program is properly setting the state to testState when it should, but the corresponding styles are NOT being set on the child components in the itemRenderer.  E.G. when the data for the renderer above is 'testValue', a black rectangle should be drawn, but is not.


      It DOES work when you set the states directly in the data setter.  However, this not the reccomended method in the docs and forums to implement custom states.


      Is this a bug or am I doing something wrong? Thanks in advance.


      - Jake
        • 1. Re: Custom View States in an itemRenderer

          The question is old - but in case someone else stumbles across it with the same problem...


          your code is right, but you have to do a little extra in order to convince the ItemRenderer that it needs to reevaluate its current state. 


          check out my answer to another post here:  http://forums.adobe.com/message/3206112#3206112

          I believe that same approach outlined there will address your concerns on this issue too. 


          good luck,


          • 2. Re: Custom View States in an itemRenderer
            supersonicecho Level 2

            Thanks Lee, that worked.


            Oddly enough, the initial state is set but the MXML states are not implemented.  So if I set a renderer to say, "hover", and set a color in the MXML for "hover", it will ignore the color even though the currentState is, in fact, "hover".  Annoying as hell, and must be a bug.


            Not sure why it happens, and I don't feel like digging into the inheritance tree to find out.


            Thanks again.


            - Jake

            • 3. Re: Custom View States in an itemRenderer
              supersonicecho Level 2

              FYI - I think I see what the problem is.


              If you look at the Flex Spark ItemRenderer, they have a private flag named rendererStateDirty that is true only one time after initialization to force an initial state change.  The problem is that the state change occurs AFTER super.commitProperties so any states you set in the MXML document are ignored. 


              To fix it, your code works, or using a flag to force the state change after initialization before super.commitProperties().

              • 4. Re: Custom View States in an itemRenderer
                leecoltrane Level 1

                @Scipio_BF2, I'm glad it was helpful.  And of course, you're right - the spark ItemRenderer uses the renderStateDirty flag as a "short-circuit" to force the component to evaluate its state once at initialization, prior to the initial run of commitProperties(). Unfortunately, renderStateDirty is private, so you can't access it from your derived class, and even if you could, it wouldn't allow you to force reevaluation of the state later in the lifecycle. 


                Fortunately there is a fairly easy way to go here.  Regardless of how and when you set the state, all you have to do is call invalidateProperties() at some point *after* you made your state change.  The spark code will take care of the rest:




                if you don't call invalidateProperties(), the state will be changed, but your component will fail to render the corresponding state-dependent mxml property changes.  This is almost certainly what's going on in the case you described.



                The code I suggested is an alternate approach that shouldn't be mixed with setting the state directly.  My approach works well when all your state determination logic can encapsulated in the function getCurrentRendererState().  In that case, you would never need to call setCurrentState() directly.  Instead, you'd change the relevant properties of your application's model, and then call invalidateProperties() - and that's all. From that point, the override of commitProperties() takes care of everything else for you: it calls getCurrentRendererState(), then setCurrentState(), and finally super.commitProperties(). Because the order is enforced in commitProperties, the state will always get set *before* the super-class runs commitProperties(); and so you'll never have to worry about your state-dependent mxml not getting properly applied.


                good luck!