我有一个简单的列表和后台刷新协议。
当列表向下滚动时,刷新会将其滚动回顶部。我想阻止它。
我试过捕捉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事件。
有什么想法吗?
答案 0 :(得分: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;
}
}
答案 1 :(得分: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);
}
}
答案 2 :(得分:2)
我会尝试解释我的方法......如果你仍然不确定让我知道,我也会给你源代码。
1)创建一个变量来存储视口的当前滚动位置。 2)在滚动条上为Event.CHANGE和MouseEvent.MOUSE_WHEEL添加事件监听器,并用当前滚动位置更新在步骤1中创建的变量; 3)在视口中为FlexEvent.UpdateComplete添加事件侦听器,并将滚动位置设置为存储的变量。
简而言之,我们所做的是每当用户与其交互时将滚动位置存储在变量中,并且当我们的视口更新时(由于数据提供者更改),我们只需设置我们先前存储在滚动位置中的滚动位置。变量
答案 3 :(得分:0)
我针对这个问题的解决方案针对特定情况,但它具有非常简单的优点,因此您可以从中绘制符合您需求的内容。由于我不确切地知道你要解决的问题,我会给你一个关于我的描述:
我有一个从服务器逐步加载数据的List。当用户向下滚动并将下一批项目添加到数据提供者时,滚动位置将跳回到开头。
解决方法就像停止COLLECTION_CHANGE事件的传播一样简单,以便List不会捕获它。
myDataProvider.addEventListener(
CollectionEvent.COLLECTION_CHANGE, preventRefresh
);
private function preventRefresh(event:CollectionEvent):void {
event.stopImmediatePropagation();
}
您必须知道这有效地阻止了重新绘制List组件,因此不会显示任何添加的项目。这对我来说不是问题,因为项目将被添加到List的末尾(在视口之外),当用户滚动时,List将自动被重绘并且将显示新项目。也许在您的情况下,如果需要,您可以强制重绘。
当所有项目都已加载后,我可以删除事件监听器并返回List组件的正常行为。