更改网格高度时的滞后动画
本文关键字:滞后 动画 高度 网格 | 更新日期: 2024-10-23 01:49:10
我正试图通过更改网格的宽度来创建一个导航抽屉。
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();
}
这一切都很好,但是,宽度变化上的动画滞后了很多,有点断断续续。不管怎样,让它变得光滑?
我认为最好将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时,它就会向左移动。
为了在所有动画迭代中使用大量测量并影响性能的内容来制作控件的动画,您应该使用CacheMode设置。这将减少性能问题。这可能会有所帮助。
CacheMode="BitmapCache"
此外,您可以尝试为动画应用不同的缓和函数,因为使用它们可以最大限度地减少实际滞后。最后的建议是关于环境——如果这种行为发生在模拟设备上,请尝试在实际连接的设备上复制,因为模拟从来都不是完美的选择。
试过你的xaml。我没有看到太多的滞后,但动画似乎不是很线性。
我个人的建议是,尽量减少xaml容器,在某些情况下,您只对一个子对象使用stackNels,因此它们是无用的,但所有容器在动画时都会调用所有子对象的度量计算方法。您的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故事板已经针对animatedGrid),因此animatedGrid不会重新计算度量值,因为它有一个固定宽度的子级。
<Grid Name="animatedGrid" Width="400">
<Grid Name="leftpanel" Width="400">
...
然后你的codeBehind转换成
if (animatedGrid.Width > 0){
HideAnimation.Begin();
}
else{
OpenAnimation.Begin();
}