Home > Flex 4 Examples > Flex 4 List remembering verticalScrollPosition

Flex 4 List remembering verticalScrollPosition

A simple requirement, but ~6 hours of frustration.

All I wanted to do was to remember the scroll position that the user was at after an update of the dataprovider items on a list occurred. I had a solution in flex 3 for the (Advanced)DataGrid control that listened for a scroll event and remembered the last known scroll position that would then be set in commit properties after the dataProvider for the grid dispatched a COLLECTION_CHANGE event.

Naturally, I started with that same solution on the Flex 4 list. It was a little trickier, discovering that no event was fired from the list when a scroll event occurred. It turns out that in the skin class, you have to listen to the vertical scroll bar on the scroller object, but this of course is entirely dependent on where your scroller or viewport container that handles scrolling lives, regardless of skinclass.

So once setup, and listening for the event and remembering the scroll position, I still noticed that the list would scroll to the top of the list before snapping back to where it was – LAME.

After a couple of hours of tinkering and messing around, and a couple of failed attempts at figuring out what was setting the vertical scroll position to 0, I had an “I’VE HAD IT!” moment. I finally decided to watch the Datagroup (the scroller’s viewport) in stead of the scroller itself and low and behold, after setting up the scenario with a breakpoint finally in the right place, the following was discovered:

spark.components::DataGroup::commitProperties()

            // Don't reset the scroll positions until the new ItemRenderers have been
            // created, see bug https://bugs.adobe.com/jira/browse/SDK-23175
            if (dataProviderChanged)
            {
                dataProviderChanged = false;
                verticalScrollPosition = horizontalScrollPosition = 0;
            }

That’s lame. What are the places where dataProviderChanged is set to true? The exact condition I was using to set the scroll position to what I wanted. Guess what, the data provider hadn’t changed like their bug suggests, but only a refresh of the provider in stead.

The fix?

package
{
	import mx.collections.IList;
	import mx.events.CollectionEvent;
	
	import spark.components.DataGroup;
	
	public class DataGroup extends spark.components.DataGroup
	{
		private var _dataProviderChanged:Boolean;
		private var _lastScrollPosition:Number = 0;
		
		public function DataGroup()
		{
			super();
		}
		
		override public function set dataProvider(value:IList):void
		{
			if ( dataProvider != null && value != dataProvider )
			{
				dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE, onDataProviderChanged);
			}
			super.dataProvider = value;
			
			if ( value != null )
			{
				value.addEventListener(CollectionEvent.COLLECTION_CHANGE, onDataProviderChanged);
			}
		}
		
		override protected function commitProperties():void
		{
			var lastScrollPosition:Number = _lastScrollPosition;
			
			super.commitProperties();
			
			if ( _dataProviderChanged )
			{
				verticalScrollPosition = lastScrollPosition;
			}
		}
		
		private function onDataProviderChanged(e:CollectionEvent):void
		{
			_dataProviderChanged = true;
			invalidateProperties();
		}
		
		
		override public function set verticalScrollPosition(value:Number):void
		{
			super.verticalScrollPosition = value;
			_lastScrollPosition = value;
		}
	}
}

I’ve created a bug report for this if anyone is interested.

Advertisement
  1. June 18, 2010 at 7:24 PM | #1

    Does it help to listen for scroll position changes via the layout rather than a scrollbar?

    See http://forums.adobe.com/message/2872718 for an example.

    • roustalski
      June 22, 2010 at 7:56 AM | #2

      It doesn’t help the problem described in the post, but I do think that is a better solution than listening to the vertical scroll bar on the scroller.

  2. October 21, 2010 at 1:06 PM | #3

    Thanks for finding this out, I’m implementing something similar tomorrow, maybe this will speed it up a bit.

  3. James
    June 10, 2011 at 6:55 AM | #4

    How would you implement this in a mx component?

  4. June 22, 2011 at 9:27 AM | #6

    I try to implement this using a (spark) DataGrid with a custom Grid class implementing your methods and assigned to the DataGrid in a custom skin. However, it doesn’t work and wonder what could be the difference.

    DataGroup and Grid are both subclasses of GroupBase, I guess this is why I could copy and paste your code into the custom Grid class. But there seems to be a difference preventing your solution to work. Do you have an idea?

    • August 31, 2011 at 8:45 AM | #7

      Sorry Rico,

      Nothing stands out from your description, but if you want to email me your project or a sample, I don’t mind taking a look at it.

  5. Nad
    September 25, 2011 at 4:39 AM | #8

    Hi;
    I’m not sure how to use the provided package. I’ve created a DataGroup.as file in my default package folder and pasted the code package code there. But that had no effect on my project.

    Please assist.

    • roustalski
      September 25, 2011 at 1:32 PM | #9

      Hello,

      Did you create a skinclass for the s:List control and then in the custom skin class reference the DataGroup.as file in the skin?

  6. Nad
    September 26, 2011 at 1:10 AM | #10

    Thanks for the tip, I’ve tried the following, but didn’t get far:
    [1]
    Created a skin for the s:List (File-> New-> MXML Skin) and
    - named it List_Skin,
    - Host Component -> List
    - Create Copy of -> spark.skins.spark.ListSkin
    [2]
    in the skin file (List_Skin.mxml) I:
    - Added: import DataGroup;
    - Searched for <s:DataGroup and replaced it with <local:DataGroup

    But it didn't compile then complaining about within the DataGroup.

    If it’s not much trouble, would you please attach to the article a sample project. I’m sure it will help many, as I couldn’t find any reference in the Internet for remembering scroll position based on COLLECTION_CHANGE other than this one.

    Thanks

  7. Nad
    September 27, 2011 at 3:11 AM | #12

    Thanks;
    I’ve got it to work by using <local:layout instead of <s:layout in the List_Skin file. It now reads:

    Thanks you very much for your help
    /Nad

  1. August 2, 2010 at 2:09 PM | #1
  2. June 14, 2011 at 6:39 AM | #2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.