1

我有一个简单的列表和一个后台刷新协议。

当列表向下滚动时,刷新会将其滚动回顶部。我想阻止这一切。

我尝试捕捉 COLLECTION_CHANGE 事件并

validateNow();   //  try to get the component to reset to the new data

list.ensureIndexIsVisible(previousIndex);    //  actually, I search for the previous data id in the IList, but that's not important

这会失败,因为列表在更改会自行重置(在 DataGroup.commitProperties 中)。

我讨厌使用 Timer、ENTER_FRAME 或 callLater(),但我似乎想不出办法。

我能看到的唯一其他选择是对 List 进行子类化,以便它可以捕获皮肤中的 DataGroup 正在抛出的 dataProviderChanged 事件。

有任何想法吗?

4

4 回答 4

4

实际上,更好的解决方案是扩展 DataGroup。您需要覆盖它。

此处的所有解决方案都会在滚动条重置为 0 并将其设置回之前的值时产生闪烁。那看起来不对。此解决方案工作时没有任何闪烁,最棒的是,您只需在代码中将 DataGroup 更改为 FixedDataGroup 即可工作,无需对代码进行其他更改;)。

享受伙计们。

public class FixedDataGroup extends spark.components.DataGroup
{
    private var _dataProviderChanged:Boolean;
    private var _lastScrollPosition:Number = 0;

    public function FixedDataGroup()
    {
        super();
    }

    override public function set dataProvider(value:IList):void
    {
        if ( this.dataProvider != null && value != this.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;
    }


}
于 2012-01-03T15:26:56.550 回答
2

我以前遇到过这个问题,并通过使用带有匹配器的数据代理模式来解决它。为您的集合编写一个匹配器,通过仅更新已更改的对象和仅更新现有对象的属性来支持您的列表。目标是避免在数据源刷新时创建新对象。

当列表有新数据时(刷新后),循环浏览新数据对象列表,将这些对象的属性复制到支持列表的集合中的对象中。通常,您将根据 id 匹配对象。新列表中不存在于旧列表中的任何对象都将被添加。您的滚动位置通常不会改变,并且通常会保留任何选择。

这是一个例子。

for each(newObject:Object in newArrayValues){
  var found:Boolean = false;
  for each(oldObject:Object in oldArrayValues){
    if(oldObject.id == newObject.id){
      found = true;
      oldObject.myAttribute = newObject.myAttribute;
      oldObject.myAttribute2 = newObject.myAttribute2;
    }
  }
  if(!found){
    oldArrayValues.addItem(newObject);
  }
}
于 2011-06-30T21:31:38.843 回答
2

我将尝试解释我的方法...如果您仍然不确定,请告诉我,我也会给您源代码。

1)创建一个变量来存储视口的当前滚动位置。2)在滚动条上添加Event.CHANGE和MouseEvent.MOUSE_WHEEL的事件监听器,并用当前滚动位置更新步骤1中创建的变量;3) 在您的视口中为 FlexEvent.UpdateComplete 添加一个事件侦听器,并将滚动位置设置为存储的变量。

简而言之,我们所做的就是在每次用户与其交互时将滚动位置存储在变量中,当我们的视口更新时(由于数据提供者更改),我们只需设置之前存储在变量中的滚动位置。

于 2011-06-30T23:54:03.417 回答
-1

我对这个问题的解决方案是针对特定情况,但它的优点是非常简单,所以也许你可以从中得出适合你需要的东西。由于我不确切知道您要解决什么问题,所以我会给您一个描述:

我有一个从服务器逐步加载数据的列表。当用户向下滚动并将下一批项目添加到数据提供者时,滚动位置将跳回开始。

解决方案很简单,就是停止 COLLECTION_CHANGE 事件的传播,这样 List 就不会捕获它。

myDataProvider.addEventListener(
    CollectionEvent.COLLECTION_CHANGE, preventRefresh
);

private function preventRefresh(event:CollectionEvent):void {
    event.stopImmediatePropagation();
}

您必须知道这有效地防止了 List 组件的重绘,因此不会显示任何添加的项目。这对我来说不是问题,因为项目将添加到列表的末尾(视口之外),当用户滚动时,列表将自动重绘并显示新项目。也许在您的情况下,如果需要,您可以强制重绘。

加载完所有项目后,我可以删除事件侦听器并返回 List 组件的正常行为。

于 2011-07-01T09:40:35.320 回答