Canvas Scroll Policy Madness

While building a custom control for a client, I noticed an odd behavior in the ScrollPolicy for the various containers (I was specifically working with Canvas when i discovered this). 

When the vScrollPolicy of a container is set to off, this not only removes the scrollbars, but also removes the ability to set the vPosition programatically.  The ASDocs for this make no mention of this restriction, but simply describe the scroll policy as:

vScrollPolicy

vScrollPolicy: String  

Whether the vertical scroll bar is always present, always absent, or automatically added when needed. Possible values are on, off, and auto. The default value is auto.

To simply demostrate the issue, i worked with this ultra simplified example:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="
http://www.macromedia.com/2003/mxml" initialize="buildDummyArray()" backgroundColor="#ffffff">
<mx:Label text="This is only a test"/>
<mx:Canvas id="foo" vScrollPolicy="off" height="200" >
 <mx:Repeater id="rep" dataProvider="{testArray}">
  <mx:Label text="{rep.currentItem}" y="{rep.currentIndex*20}" />
 </mx:Repeater>
</mx:Canvas>
 <mx:Button label="Page Up" click="foo.vPosition-=100" />
 <mx:Button label="Page Down" click="foo.vPosition+=100"/>
 <mx:CheckBox id="cb" label="V Scroll Policy" click="setScrollPolicy()"/>

 <mx:Script>
 <![CDATA[
  var testArray:Array;
  function setScrollPolicy (){
   if(cb.selected){
    foo.vScrollPolicy = "on";
   } else {
    foo.vScrollPolicy = "off";
   }
  }
  function buildDummyArray(){
   testArray = new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
  }
 ]]>
 </mx:Script>

</mx:Application>

You can see this running here.  Notice that checking and unchecking the checkbox not only effects the scrollbars showing, but also changes whether the buttons work.  (even odder, setting vScrollPolicy="off" seems to automatically reset the vPosition to 0.

My first quick and dirty solution was to simply lay an empty container over the scroll bar, so it couldnt be seen, not particularly elegant, but temporarily solved the problem.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="
http://www.macromedia.com/2003/mxml" initialize="buildDummyArray()" backgroundColor="#ffffff">
<mx:Label text="This is only a test"/>
<mx:Canvas vScrollPolicy="off" width="100%" height="100%">
 <mx:Canvas id="foo" vScrollPolicy="on" height="200" x="0" y="0">
  <mx:Repeater id="rep" dataProvider="{testArray}">
   <mx:Label text="{rep.currentItem}" y="{rep.currentIndex*20}" />
  </mx:Repeater>
 </mx:Canvas>
 <mx:Box backgroundColor="#ffffff" height="{foo.height}" width="20" x="{foo.width-20}" y="0"/>
</mx:Canvas>
 <mx:Button label="Page Up" click="foo.vPosition-=100" />
 <mx:Button label="Page Down" click="foo.vPosition+=100"/>
 <mx:Script>
 <![CDATA[
  var testArray:Array;
  function buildDummyArray(){
   testArray = new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
  }
 ]]>
 </mx:Script>

</mx:Application>

In response to my question about this on the flexcoders list, Manish Jethani came up with an interesting solution: 

I found that there’s an undocumented function called scrollChildren that you can call to scroll the children in the absence of scrollbars:

  <mx:Button label="Page Up" click="foo.scrollChildren(0, -100)" />
  <mx:Button label="Page Down" click="foo.scrollChildren(0, 100)"/>

Note: Since it’s undocumented, it’s not supported (and may break your
code with future versions of Flex).

Trying his solution, I came up with this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="
http://www.macromedia.com/2003/mxml" initialize="buildDummyArray()" backgroundColor="#ffffff">
<mx:Label text="This is only a test"/>
<mx:Canvas id="foo" vScrollPolicy="off" height="200" >
 <mx:Repeater id="rep" dataProvider="{testArray}">
  <mx:Label text="{rep.currentItem}" y="{rep.currentIndex*20}" />
 </mx:Repeater>

</mx:Canvas>
 <mx:Button label="Page Up" click="foo.scrollChildren(0, -100)"/>
 <mx:Button label="Page Down" click="foo.scrollChildren(0,100)"/>
 
 <mx:Script>
 <![CDATA[
  var testArray:Array;
  function buildDummyArray(){
   testArray = new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
  }
 ]]>
 </mx:Script>

</mx:Application>

Of course, this isnt perfect either, since a) it uses undocumented methods and b) requires further logic to ensure the user doesnt scroll past the begining or end (keep click the buttons to see what i mean).  Actually, quick testing shows this is harder than expected, since using scrollChildren to change the vPosition doesnt actually update the vPosition property. 

There are no comments.

Leave a Reply