【问题标题】:Laggy animation on changing height of grid改变网格高度的滞后动画
【发布时间】:2015-03-07 12:23:01
【问题描述】:

我正在尝试通过更改 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();



    }

这一切都很好,但是,宽度变化的动画滞后了很多,有点口吃。无论如何让它顺利?

【问题讨论】:

    标签: c# xaml animation windows-phone-8


    【解决方案1】:

    我认为动画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 时,它只是向左移动。

    【讨论】:

      【解决方案2】:

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

      CacheMode="BitmapCache"
      

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

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

      我的个人建议 - 尝试最小化 xaml 容器,在某些情况下,您使用只有一个孩子的 stackPanel,因此它们没有用,但所有容器在动画时都会为所有孩子调用度量计算方法。您的 xaml 填充了带有图像的文本块的重复容器 - 尝试使用新的 controltemplate 创建样式,这将非常有帮助(但不是主要目标,如果需要,您可以在该模板上设置 CacheMode - 这只是建议)。您可以将情节提要从代码隐藏提取到 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>
      

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

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

      然后你的codeBehind转换成

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

      【讨论】:

      • 没有太大帮助.. 已经在实际设备上试用.. Lumia 920
      • 您能否提供更具体的网格内容示例,因为我试图重现它,但空网格或具有 20 个按钮的网格动画效果没有任何性能影响。此外,尝试将缓存模式应用于自定义控件(如果有),特别是包含图像或使用透明度的控件。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-18
      • 1970-01-01
      • 2021-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多