改变网格高度的滞后动画

Laggy animation on changing height of grid

我正在尝试通过更改网格的宽度来创建导航抽屉。

XAML :

<Grid x:Name="LayoutRoot" Width="900" Margin="0,0,0,0">
    <!--<Grid.ColumnDefinitions>
        <ColumnDefinition Width="400"/>
        <ColumnDefinition Width="500"/>
    </Grid.ColumnDefinitions>-->
    <toolkit:GestureService.GestureListener>
        <toolkit:GestureListener Flick="OnFlick"/>
    </toolkit:GestureService.GestureListener>
    <StackPanel Orientation="Horizontal">
        <!-- left panel... keep width as 0 when app starts-->
        <Grid Name="leftpanel" Width="400">
            <StackPanel>
                <Image 
                    Source="/Images/dp.png" 
                    Margin="0,40" 
                    x:Name="myimage" 
                    Tap="myimage_Tap" 
                    Height="120" 
                    Width="120" 
                    Stretch="Fill" 
                    RenderTransformOrigin="0.5, 0.5">
                    <Image.Clip>
                        <EllipseGeometry
                                Center="60,60"
                                RadiusX="60"
                                RadiusY="60" />
                    </Image.Clip>
                    <Image.RenderTransform>
                        <RotateTransform x:Name="rotateTransform"/>
                    </Image.RenderTransform>
                </Image>
                <TextBlock
                    Foreground="White"
                    Text="name"
                    HorizontalAlignment="Center"
                    Margin="0,-20,0,0"
                    FontWeight="ExtraBold"/>
                <StackPanel 
                    Orientation="Horizontal" 
                    HorizontalAlignment="Center"
                    Margin="0,5">
                    <Image Source="/Images/loc.png"
                           Height="30"
                           Width="30"/>

                </StackPanel>

                <StackPanel 
                    Orientation="Horizontal" 
                    HorizontalAlignment="Left"
                    Margin="20,30,0,0">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock
                    Foreground="White"
                    Text="text"
                        FontSize="35"
                        Margin="20,0"
                    HorizontalAlignment="Center"/>
                </StackPanel>
                <StackPanel 
                    Orientation="Horizontal" 
                    HorizontalAlignment="Left"
                    Margin="20,20,0,0"
                    Name="x">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock
                    Foreground="White"
                    Text="text"
                        FontSize="35"
                        Margin="20,0"
                    HorizontalAlignment="Center"/>
                </StackPanel>
                <StackPanel 
                    Orientation="Horizontal" 
                    HorizontalAlignment="Left"
                    Margin="20,20,0,0">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock
                    Foreground="White"
                    Text="Moments"
                        FontSize="35"
                        Margin="20,0"
                    HorizontalAlignment="Center"/>
                </StackPanel>
                <StackPanel 
                    Orientation="Horizontal" 
                    HorizontalAlignment="Left"
                    Margin="20,20,0,0">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock
                    Foreground="White"
                    Text="text"
                        FontSize="35"
                        Margin="20,0"
                    HorizontalAlignment="Center"/>
                </StackPanel>
                <StackPanel 
                    Orientation="Horizontal" 
                    HorizontalAlignment="Left"
                    Margin="20,20,0,0">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock
                    Foreground="White"
                    Text="x"
                        FontSize="35"
                        Margin="20,0"
                    HorizontalAlignment="Center"/>
                </StackPanel>
                <StackPanel 
                    Orientation="Horizontal" 
                    HorizontalAlignment="Left"
                    Margin="20,20,0,0">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock
                    Foreground="White"
                    Text="text"
                        FontSize="35"
                        Margin="20,0"
                    HorizontalAlignment="Center"/>
                </StackPanel>
                <Line X1="0" X2="1"
                    Margin="0,20,0,0"
                    Stroke="White"
                    StrokeThickness="1"
                    Stretch="Fill"
                    VerticalAlignment="Center"/>
                <StackPanel
                    Orientation="Horizontal"
                    Height="80">
                    <Button 
                        BorderThickness="0" 
                        Width="199"
                        Height="80">
                        <StackPanel Orientation="Horizontal">
                            <Image 
                                Source="/Images/x.png"
                                Height="35"
                                Width="35"/>
                            <TextBlock 
                                Text="text"
                                Margin="10,0"
                                FontSize="35"/>
                        </StackPanel>
                    </Button>
                    <Line X1="0"  Y2="100"

                    Stroke="White"
                    StrokeThickness="1"
                    Stretch="Fill"
                    HorizontalAlignment="Center"/>
                    <Button 
                        BorderThickness="0" 
                        Width="199"
                        Height="80">
                        <StackPanel Orientation="Horizontal">
                            <Image 
                                Source="/Images/x.png"
                                Height="35"
                                Width="35"/>
                            <TextBlock 
                                Text="text"
                                Margin="10,0"
                                FontSize="35"/>
                        </StackPanel>
                    </Button>
                </StackPanel>

            </StackPanel>
        </Grid>
        <Grid Width="500" x:Name="mainpanel" Background="Black">
        </Grid>


    </StackPanel>
</Grid>

隐藏代码:

private void OnFlick(object sender, FlickGestureEventArgs e)
    {


        if (e.Direction == System.Windows.Controls.Orientation.Horizontal)
        {

            // User flicked towards left ==== show main panel
            if (e.HorizontalVelocity < 0)
            {
                if (leftpanel.Width > 0)    
                {

                    Slideright(leftpanel);

                }
            }

            // User flicked towards right  ===== show left panel
            if (e.HorizontalVelocity > 0)
            {
                if (leftpanel.Width < 400)
                {
                    Slideleft(leftpanel);
                }
            }
        }
    }

    private void Slideleft(Grid leftpanel)
    {
        DoubleAnimation tAnimation = new DoubleAnimation();
        tAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.3));
        tAnimation.From = 0;
        tAnimation.To = 400;
        Storyboard.SetTarget(tAnimation, leftpanel);
        Storyboard.SetTargetProperty(tAnimation, new PropertyPath(Grid.WidthProperty));
        Storyboard storyboard = new Storyboard();
        storyboard.Children.Add(tAnimation);
        storyboard.Begin();



    }

    private void Slideright(Grid leftpanel)
    {
        //throw new NotImplementedException();

        DoubleAnimation tAnimation = new DoubleAnimation();
        tAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.3));
        tAnimation.From = 400;
        tAnimation.To = 0;
        Storyboard.SetTarget(tAnimation, leftpanel);
        Storyboard.SetTargetProperty(tAnimation, new PropertyPath(Grid.WidthProperty));
        Storyboard storyboard = new Storyboard();
        storyboard.Children.Add(tAnimation);
        storyboard.Begin();



    }

一切正常,但是,宽度变化时的动画滞后很多,有点卡顿。无论如何让它顺利?

为了在所有动画迭代中使用大量测量和损害性能的内容对控件进行动画处理,您应该使用 CacheMode 设置。这将减少性能问题。 这可能会有所帮助。

CacheMode="BitmapCache"

您也可以尝试为动画应用不同的缓动函数,因为使用它们可以最大程度地减少实际延迟。最后的建议是关于环境的——如果这种行为发生在模拟设备上,请尝试在实际连接的设备上重现它,因为模拟永远不是完美的选择。

尝试了您的 xaml。我没有看到太多延迟,但动画似乎不是很线性。

我的个人建议-尽量减少xaml容器,在某些情况下你只使用一个child的stackPanels,所以它们是无用的,但所有容器都会调用所有[=的度量计算方法36=]ren 同时动画。您的 xaml 充满了带有图像的文本块的复制容器 - 尝试使用新的控制模板创建样式,这将非常有帮助(但不是为了主要目标,如果需要,您可以在该模板上设置 CacheMode - 这只是建议).您可以将故事板从 code-behind 提取到 xaml,这样它们将是静态的,无需重新创建。

 <Grid.Resources>
        <Storyboard x:Key="Hide" x:Name="HideAnimation">
            <DoubleAnimation Duration="0:0:0.333" From="400" To="0" Storyboard.TargetName="animatedGrid" Storyboard.TargetProperty="Width"/>
        </Storyboard>
        <Storyboard x:Key="Open" x:Name="OpenAnimation">
            <DoubleAnimation Duration="0:0:0.333" From="0" To="400" Storyboard.TargetName="animatedGrid" Storyboard.TargetProperty="Width"/>
        </Storyboard>
    </Grid.Resources>

在您的特定情况下,动画非常简单,您完全可以避免对容器元素采取 re-calculating 措施!只需将 leftPanel 包裹在动画网格中(我的 xaml 故事板已经针对 animatedGrid)所以 animatedGrid 不会重新计算度量,因为它有一个固定宽度的 child。

<Grid Name="animatedGrid" Width="400">
        <Grid Name="leftpanel" Width="400"> 
...

那么你的codeBehind就变成了

if (animatedGrid.Width > 0){
    HideAnimation.Begin();
}
else{
    OpenAnimation.Begin();
}

我认为动画 RenderTransform 的参数而不是复杂的控件大小是更好的主意。您的代码中还有太多不必要的网格和堆栈面板,它们会降低您的应用程序的速度。

这是我的解决方法。翻译动画很流畅,因为它们由 GPU 处理。如果某些动画改变了控件的大小,则必须涉及 CPU 以重新计算每一帧的新布局,所以这很糟糕。我已经删除了这种动画并用简单流畅的翻译代替它们。

XAML:

<Grid x:Name="LayoutRoot" Width="900" Margin="0,0,0,0">
    <Grid.Resources>
        <Storyboard x:Name="SlideLeftAnimation">
            <DoubleAnimation Storyboard.TargetName="leftpanel"
                             Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
                             To="-400"
                             Duration="00:00:00.5">
                <DoubleAnimation.EasingFunction>
                    <QuarticEase EasingMode="EaseOut" />
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
        <Storyboard x:Name="SlideRightAnimation">
            <DoubleAnimation Storyboard.TargetName="leftpanel"
                             Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
                             To="0"
                             Duration="00:00:00.5">
                <DoubleAnimation.EasingFunction>
                    <QuarticEase EasingMode="EaseOut" />
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
    </Grid.Resources>
    <Grid.Background>
        <StaticResource ResourceKey="PhoneBackgroundBrush"/>
    </Grid.Background>
    <toolkit:GestureService.GestureListener>
        <toolkit:GestureListener Flick="OnFlick"/>
    </toolkit:GestureService.GestureListener>
    <!-- left panel... keep width as 0 when app starts-->
    <StackPanel Name="leftpanel" Width="400"
                    HorizontalAlignment="Left">
        <StackPanel.RenderTransform>
            <TranslateTransform X="-400"/>
        </StackPanel.RenderTransform>
        <Image 
                Source="/Images/dp.png" 
                Margin="0,40" 
                x:Name="myimage" 
                Tap="myimage_Tap" 
                Height="120" 
                Width="120" 
                Stretch="Fill" 
                RenderTransformOrigin="0.5, 0.5">
            <Image.Clip>
                <EllipseGeometry
                            Center="60,60"
                            RadiusX="60"
                            RadiusY="60" />
            </Image.Clip>
            <Image.RenderTransform>
                <RotateTransform x:Name="rotateTransform"/>
            </Image.RenderTransform>
        </Image>
        <TextBlock
                Foreground="White"
                Text="name"
                HorizontalAlignment="Center"
                Margin="0,-20,0,0"
                FontWeight="ExtraBold"/>
        <StackPanel 
                Orientation="Horizontal" 
                HorizontalAlignment="Center"
                Margin="0,5">
            <Image Source="/Images/loc.png"
                       Height="30"
                       Width="30"/>

        </StackPanel>

        <StackPanel 
                Orientation="Horizontal" 
                HorizontalAlignment="Left"
                Margin="20,30,0,0">
            <Image Source="/Images/x.png"
                       Height="35"
                       Width="35"/>
            <TextBlock
                Foreground="White"
                Text="text"
                    FontSize="35"
                    Margin="20,0"
                HorizontalAlignment="Center"/>
        </StackPanel>
        <StackPanel 
                Orientation="Horizontal" 
                HorizontalAlignment="Left"
                Margin="20,20,0,0"
                Name="x">
            <Image Source="/Images/x.png"
                       Height="35"
                       Width="35"/>
            <TextBlock
                Foreground="White"
                Text="text"
                    FontSize="35"
                    Margin="20,0"
                HorizontalAlignment="Center"/>
        </StackPanel>
        <StackPanel 
                Orientation="Horizontal" 
                HorizontalAlignment="Left"
                Margin="20,20,0,0">
            <Image Source="/Images/x.png"
                       Height="35"
                       Width="35"/>
            <TextBlock
                Foreground="White"
                Text="Moments"
                    FontSize="35"
                    Margin="20,0"
                HorizontalAlignment="Center"/>
        </StackPanel>
        <StackPanel 
                Orientation="Horizontal" 
                HorizontalAlignment="Left"
                Margin="20,20,0,0">
            <Image Source="/Images/x.png"
                       Height="35"
                       Width="35"/>
            <TextBlock
                Foreground="White"
                Text="text"
                    FontSize="35"
                    Margin="20,0"
                HorizontalAlignment="Center"/>
        </StackPanel>
        <StackPanel 
                Orientation="Horizontal" 
                HorizontalAlignment="Left"
                Margin="20,20,0,0">
            <Image Source="/Images/x.png"
                       Height="35"
                       Width="35"/>
            <TextBlock
                Foreground="White"
                Text="x"
                    FontSize="35"
                    Margin="20,0"
                HorizontalAlignment="Center"/>
        </StackPanel>
        <StackPanel 
                Orientation="Horizontal" 
                HorizontalAlignment="Left"
                Margin="20,20,0,0">
            <Image Source="/Images/x.png"
                       Height="35"
                       Width="35"/>
            <TextBlock
                Foreground="White"
                Text="text"
                    FontSize="35"
                    Margin="20,0"
                HorizontalAlignment="Center"/>
        </StackPanel>
        <Line X1="0" X2="1"
                Margin="0,20,0,0"
                Stroke="White"
                StrokeThickness="1"
                Stretch="Fill"
                VerticalAlignment="Center"/>
        <StackPanel
                Orientation="Horizontal"
                Height="80">
            <Button 
                    BorderThickness="0" 
                    Width="199"
                    Height="80">
                <StackPanel Orientation="Horizontal">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock 
                        Text="text"
                        Margin="10,0"
                        FontSize="35"/>
                </StackPanel>
            </Button>
            <Line X1="0" Y2="100"
                Stroke="White"
                StrokeThickness="1"
                Stretch="Fill"
                HorizontalAlignment="Center"/>
            <Button BorderThickness="0" 
                    Width="199"
                    Height="80">
                <StackPanel Orientation="Horizontal">
                    <Image Source="/Images/x.png"
                           Height="35"
                           Width="35"/>
                    <TextBlock Text="text"
                               Margin="10,0"
                               FontSize="35"/>
                </StackPanel>
            </Button>
        </StackPanel>
    </StackPanel>
    <Grid Width="500" x:Name="mainpanel" Background="Black"
      HorizontalAlignment="Right">
    </Grid>
</Grid>

C#

private void OnFlick(object sender, FlickGestureEventArgs e)
    {
        if (e.Direction == System.Windows.Controls.Orientation.Horizontal)
        {
            // User flicked towards left ==== show main panel
            if (e.HorizontalVelocity < 0)
            {
                SlideLeftAnimation.Begin();
            }
            // User flicked towards right  ===== show left panel
            else if (e.HorizontalVelocity > 0)
            {
                SlideRightAnimation.Begin();
            }
        }
    }

如您所见,无需在代码隐藏中创建故事板。在我的示例中,它们都在 XAML 中作为您的主要 Grid 的资源。

请注意,我已将 TranslateTransform 添加到您的 leftpanel。很重要。

<StackPanel.RenderTransform>
    <TranslateTransform X="-400"/>
</StackPanel.RenderTransform>

当您将 X 值设置为 0 时,面板可见。但是当你将它设置为 -400 时,它只是向左移动。