ListBox项加载动画

7
我想创建一个基于ListBox(或ListView)的用户控件,并带有以下动画效果:列表框中的项不会一次性全部加载,它们必须逐步加载(逐个项目,先第一个,然后第二个,第三个等等),并在它们之间设置一些延迟时间。
我该如何实现这个功能?
1个回答

10
你可以使用Blend SDK行为来实现这个功能:
<ListBox ItemsSource="{Binding Collection, Source={StaticResource SampleData}}">
    <i:Interaction.Behaviors>
        <b:FadeAnimateItemsBehavior Tick="0:0:0.05">
            <b:FadeAnimateItemsBehavior.Animation>
                <DoubleAnimation From="0" To="1" Duration="0:0:0.3"/>
            </b:FadeAnimateItemsBehavior.Animation>
        </b:FadeAnimateItemsBehavior>
    </i:Interaction.Behaviors>
</ListBox>
class FadeAnimateItemsBehavior : Behavior<ListBox>
{
    public DoubleAnimation Animation { get; set; }
    public TimeSpan Tick { get; set; }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
    }

    void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
        IEnumerable<ListBoxItem> items;
        if (AssociatedObject.ItemsSource == null)
        {
            items = AssociatedObject.Items.Cast<ListBoxItem>();
        }
        else
        {
            var itemsSource = AssociatedObject.ItemsSource;
            if (itemsSource is INotifyCollectionChanged)
            {
                var collection = itemsSource as INotifyCollectionChanged;
                collection.CollectionChanged += (s, cce) =>
                    {
                        if (cce.Action == NotifyCollectionChangedAction.Add)
                        {
                            var itemContainer = AssociatedObject.ItemContainerGenerator.ContainerFromItem(cce.NewItems[0]) as ListBoxItem;
                            itemContainer.BeginAnimation(ListBoxItem.OpacityProperty, Animation);
                        }
                    };

            }
            ListBoxItem[] itemsSub = new ListBoxItem[AssociatedObject.Items.Count];
            for (int i = 0; i < itemsSub.Length; i++)
            {
                itemsSub[i] = AssociatedObject.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
            }
            items = itemsSub;
        }
        foreach (var item in items)
        {
            item.Opacity = 0;
        }
        var enumerator = items.GetEnumerator();
        if (enumerator.MoveNext())
        {
            DispatcherTimer timer = new DispatcherTimer() { Interval = Tick };
            timer.Tick += (s, timerE) =>
            {
                var item = enumerator.Current;
                item.BeginAnimation(ListBoxItem.OpacityProperty, Animation);
                if (!enumerator.MoveNext())
                {
                    timer.Stop();
                }
            };
            timer.Start();
        }
    }
}

Tick指定了项目开始淡入的时间间隔。Animation是应用于淡入透明度的动画,可以在Xaml中设置以实现高度自定义(例如缓动函数和淡入时间)。

编辑:添加了新的项目淡入效果(仅在使用INotifyCollectionChangedItemsSource中有效)

请谨慎使用此类代码段,如果使用的话。这段代码主要是为了演示目的,并给出如何处理这个问题的一般想法。如果可用,这也可能使用Blend 4的本机FluidMoveBehaviors完成。


谢谢您提供如此专业的答案!最后,我该如何使用Visibility属性而不是Opacity属性来实现动画效果呢?我尝试了很多次,但都无法做到。 - JaneKate
您可以使用 ObjectAnimationUsingKeyFrames 来实现可见性动画效果,在 这个答案 中有一个示例。 - H.B.
谢谢!由于这种动画(或行为)没有特定的名称(手风琴?-也许是最好的!),所以很难找到答案。 - JaneKate
很高兴能够帮助到您。如果这回答了您的问题,您可以通过点击答案左侧的勾勾轮廓接受它。 - H.B.
我该如何在装满形状的画布中使用它? - George R
@GeorgeR:你可以使用 ItemsControl 并将其 ItemsPanel 设置为 Canvas,然后绑定 ItemsSource 并对其应用此行为(需要更改行为目标类型)。 - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接