LongListSelector 中的缓慢故事板动画 [英] Slow storyboard animation inside LongListSelector

查看:27
本文介绍了LongListSelector 中的缓慢故事板动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 LongListSelector,其中填充了一些项目.每个项目都有一个子菜单,可以使用滑动动画显示或折叠.问题是动画非常慢,具体取决于您在列表中点击哪个项目.开头和结尾都很慢,中间很流畅.我怀疑每个动画帧都会使 longlistselector 失效,这意味着整个视觉树必须更新它的布局.

我使用数据触发器来启动动画.因此,我可以看到许多其他项目的触发器也被触发,这表明它们正在被重绘.它还表明,当您点击列表中间时,触发的其他项目也少得多.奇怪...

我在github上托管了测试项目: 而不是标准的 RenderTransform.经过一些调整后,这工作得很好,但是 layouttranform 将它以缓慢的依赖动画的形式返回...

解决方案

您是正确的,更改 UserControl 高度会导致可视化树的大部分无效,但这是必需的,并且是设计使然.问题是您正在修改故事板中的控件高度,这不是一个独立的动画,无法在合成器上运行.

阅读 http://msdn.microsoft.com/en-us/library/windows/apps/jj819807.aspx#dependent 尽管这是针对 Windows 商店应用程序(并且 SL 中有 EnableDependentAnimations 标志),但想法保持不变.您需要找到一种使用独立动画扩展项目的方法,可能是使用 ScaleTransform.

I have a LongListSelector which is populated with some items. Each item has a submenu which can be visible or collapsed using a sliding animation. The problem is that the animation is extremely slow depending on which item you tap in the list. At the start and the end it's slow, in the middle it's smooth. I suspect that each animation frame invalidates the longlistselector which means the entire visual tree must update it's layout.

I use a datatrigger to start the animation. Because of that I can see that the triggers on lots of other items also get fired which indicates to me they are being redrawn. It also shows that when you tap in the middle of list a lot less other items get triggered as well. weird...

I hosted the testproject on github: https://github.com/jessetabak/wpanimationproblem

The LongListSelector:

<phone:LongListSelector x:Name="LongList" Margin="0" Padding="0" ItemsSource="{Binding Items}" 
        HorizontalAlignment="Stretch" Background="Transparent">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <wegGooiApp2:ItemView />
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>

</phone:LongListSelector>

The ItemView:

<UserControl.Resources>

        <wegGooiApp2:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />

        <Storyboard x:Key="ShowMenu">
            <DoubleAnimation Storyboard.TargetProperty="(Grid.Height)" 
                             Storyboard.TargetName="Submenu"
                             From="0" To="70" Duration="0:0:0.25" />

            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Submenu"
                                           Storyboard.TargetProperty="(Grid.Visibility)">
                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                    <DiscreteObjectKeyFrame.Value>
                        <Visibility>Visible</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                </DiscreteObjectKeyFrame>
            </ObjectAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Key="HideMenu">       

            <DoubleAnimation Storyboard.TargetProperty="(Grid.Height)"
                            Storyboard.TargetName="Submenu"
                            From="70" To="0" Duration="0:0:0.25" />

            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Submenu"
                                           Storyboard.TargetProperty="(Grid.Visibility)">
                <DiscreteObjectKeyFrame KeyTime="0:0:0.25">
                    <DiscreteObjectKeyFrame.Value>
                        <Visibility>Collapsed</Visibility>
                    </DiscreteObjectKeyFrame.Value>
                </DiscreteObjectKeyFrame>
            </ObjectAnimationUsingKeyFrames>

        </Storyboard>        

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <!-- TEST ITEM -->
        <Border Height="70" BorderBrush="Red" Background="Transparent" BorderThickness="1" HorizontalAlignment="Stretch">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>

                <TextBlock Text="Test Item" HorizontalAlignment="Stretch" FontSize="42" />
                <Button Content="v" Grid.Column="1" Tap="Button_Tap" Tag="{Binding}">

                </Button>
            </Grid>
        </Border>

        <!-- SUBMENU -->
        <Border x:Name="Submenu" Grid.Row="1" BorderBrush="Green" BorderThickness="1" 
                Visibility="{Binding SubMenuIsVisible, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneTime}"
                Background="Green" Height="0" Margin="0 0 0 0">

            <i:Interaction.Triggers>
                <ec:DataTrigger Binding="{Binding SubMenuIsVisible}" Value="True">
                    <ec:CallMethodAction MethodName="MenuEnabled"
                                            TargetObject="{Binding ElementName=ThisUserControl, Mode=OneWay}" />

                </ec:DataTrigger>

                <ec:DataTrigger Binding="{Binding SubMenuIsVisible}" Value="False">
                    <ec:CallMethodAction MethodName="MenuDisabled" 
                                         TargetObject="{Binding ElementName=ThisUserControl, Mode=OneWay}" />
                </ec:DataTrigger>
            </i:Interaction.Triggers>

            <TextBlock Text="SubMenu" FontSize="42" />

        </Border>


    </Grid>
</UserControl>

The ItemView codebehind:

public partial class ItemView : UserControl
    {            
        private Storyboard _showStoryboard;
        private Storyboard _hideStoryboard;        

        public ItemView()
        {
            InitializeComponent();
            _showStoryboard = (Storyboard) this.Resources["ShowMenu"];
            _hideStoryboard = (Storyboard) this.Resources["HideMenu"];            
            Debug.WriteLine("ItemView CONSTRUCTED");
        }

        private void Button_Tap(object sender, GestureEventArgs e)
        {
            var button = (Button)sender;
            var viewModelItem = (ItemViewModel)button.Tag;

            viewModelItem.SubMenuIsVisible = !viewModelItem.SubMenuIsVisible;            
        }

        public void MenuEnabled()
        {
            Debug.WriteLine("MENU ENABLED!");
            if (Submenu.Visibility == Visibility.Collapsed)
            {
                _showStoryboard.Begin();
            }
        }

        public void MenuDisabled()
        {
            Debug.WriteLine("MENU DISABLED!");
            if (Submenu.Visibility == Visibility.Visible)
            {
                _hideStoryboard.Begin();
            }
        }        

        private void ThisUserControl_LayoutUpdated(object sender, EventArgs e)
        {
            //Debug.WriteLine("ITEMVIEW LAYOUT UPDATED!");
        }
    }

And what it looks like:

/edit 1

I tried turning it into an independent animation using a ScaleTransform, but this won't animate the surrounding ui elements. To fix this you can use a LayoutTransform instead of the standard RenderTransform. After some tweaking this worked quite nice, but the layouttranform turned it back in a slow depenpendent animation...

解决方案

You are correct that changing the UserControl height causes a large portion of the visual tree to be invalidated, but this is required, and by design. The issue is that you are modifying a controls height in a storyboard to begin with, which is not an independent animation and can't run on the compositor.

Have a read of http://msdn.microsoft.com/en-us/library/windows/apps/jj819807.aspx#dependent although this is for Windows store apps (and there is EnableDependentAnimations flag in SL), the ideas remain the same. You need to figure out a way to expand items using independent animations, probably by using a ScaleTransform.

这篇关于LongListSelector 中的缓慢故事板动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆