如何使用视觉状态为 UWP 中控件的可见性设置动画?
How can I animate the visibility of a control in UWP using Visual States?
我目前正在为我的应用程序开发一个自定义控件,它使用 header 展开和折叠内容,您可以单击它来更改状态。它的模板目前看起来像这样。
<Style TargetType="controls:ExpandControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ExpandControl">
<Border>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="State">
<VisualState x:Name="Visible">
<VisualState.Setters>
<Setter Target="Grid.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Collapsed">
<VisualState.Setters>
<Setter Target="Grid.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentPresenter x:Name="HeaderPresenter" Content="{TemplateBinding Header}" />
<Grid x:Name="Grid" Grid.Row="1">
<ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" />
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
正如您从模板中看到的那样,我目前正在使用视觉状态来设置此控件中内容的可见性,但这并不是很好的用户体验,因为内容会消失。
我希望能够以某种方式操纵内容,当控件的可见性发生变化时,内容看起来像是从 header 折叠和展开。
我看过使用 Storyboard 的动画,但我对此完全陌生,如果有人可以提供有关 Storyboard 的一些帮助以及如何使场景为我的控制工作,我将不胜感激!
提前致谢!
故事板在 Visual Studio 中并不是一个绝妙的体验,尝试手动编写它们可能不是最好的主意。
我建议您在 Blend 中打开您的项目,它是 Visual Studio 安装的一部分。它是设计应用程序的绝佳工具,特别是可以非常简单地添加 Storyboard,它会自动为您生成 Storyboard XAML,同时您可以在设计器中看到更改。
至于你的动画场景,我在一个页面中试过你的 XAML 模板,并想出了一些东西,让它看起来像是在折叠和展开,但它没有操纵可见性属性 像这样:
<VisualStateGroup x:Name="State">
<VisualState x:Name="Visible">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Grid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.1">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Grid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.2">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
您还需要将内容网格更改为如下所示:
<Grid x:Name="Grid" Grid.Row="1" RenderTransformOrigin="0.5,0">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" />
</Grid>
我将解释为什么您必须对网格进行更改以及 Storyboard 接下来要做什么。
为了实现类似于您正在寻找的东西,我在您的网格上选择了不透明度和 Y 比例来制作动画。
因为我们将操纵控件的 Y 比例,所以我们将 RenderTransform 添加到 Grid。使用 CompositeTransform 的原因是您可以操作最常见的变换(缩放、旋转、平移等)。
在状态中,我们使用关键帧来跨时间操纵值。这就是您在故事板中实现动画的方式。如果只设置一个时间为 0 的 KeyFrame,它会显示为立即更改,类似于使用更改属性的 VisualState.Setters 机制。
在折叠状态下,我们将网格的不透明度和 Y 缩放比例从 1 更改为 0。这提供了显示内容折叠到 header 中的动画。正如您从关键帧中看到的那样,我们交错了两个属性的动画,以便内容在完成缩放之前淡出。
在可见状态下,我们实质上是通过在相同的时间内将不透明度和 Y 缩放比例从 0 更改为 1 来反转折叠状态。
尝试将它们加载到您的控件中并在 Blend 中进行操作。这是一个很好的起点,因为我很快就把它们放在一起了。
您可以在此处找到有关使用 Blend 制作故事板的更多信息:https://blogs.msdn.microsoft.com/avtarsohi/2016/02/16/understand-storyboard-concept-in-xaml-using-blend-2015/
我目前正在为我的应用程序开发一个自定义控件,它使用 header 展开和折叠内容,您可以单击它来更改状态。它的模板目前看起来像这样。
<Style TargetType="controls:ExpandControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ExpandControl">
<Border>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="State">
<VisualState x:Name="Visible">
<VisualState.Setters>
<Setter Target="Grid.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Collapsed">
<VisualState.Setters>
<Setter Target="Grid.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentPresenter x:Name="HeaderPresenter" Content="{TemplateBinding Header}" />
<Grid x:Name="Grid" Grid.Row="1">
<ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" />
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
正如您从模板中看到的那样,我目前正在使用视觉状态来设置此控件中内容的可见性,但这并不是很好的用户体验,因为内容会消失。
我希望能够以某种方式操纵内容,当控件的可见性发生变化时,内容看起来像是从 header 折叠和展开。
我看过使用 Storyboard 的动画,但我对此完全陌生,如果有人可以提供有关 Storyboard 的一些帮助以及如何使场景为我的控制工作,我将不胜感激!
提前致谢!
故事板在 Visual Studio 中并不是一个绝妙的体验,尝试手动编写它们可能不是最好的主意。
我建议您在 Blend 中打开您的项目,它是 Visual Studio 安装的一部分。它是设计应用程序的绝佳工具,特别是可以非常简单地添加 Storyboard,它会自动为您生成 Storyboard XAML,同时您可以在设计器中看到更改。
至于你的动画场景,我在一个页面中试过你的 XAML 模板,并想出了一些东西,让它看起来像是在折叠和展开,但它没有操纵可见性属性 像这样:
<VisualStateGroup x:Name="State">
<VisualState x:Name="Visible">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Grid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.1">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="Grid">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Grid">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.2">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
您还需要将内容网格更改为如下所示:
<Grid x:Name="Grid" Grid.Row="1" RenderTransformOrigin="0.5,0">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" />
</Grid>
我将解释为什么您必须对网格进行更改以及 Storyboard 接下来要做什么。
为了实现类似于您正在寻找的东西,我在您的网格上选择了不透明度和 Y 比例来制作动画。
因为我们将操纵控件的 Y 比例,所以我们将 RenderTransform 添加到 Grid。使用 CompositeTransform 的原因是您可以操作最常见的变换(缩放、旋转、平移等)。
在状态中,我们使用关键帧来跨时间操纵值。这就是您在故事板中实现动画的方式。如果只设置一个时间为 0 的 KeyFrame,它会显示为立即更改,类似于使用更改属性的 VisualState.Setters 机制。
在折叠状态下,我们将网格的不透明度和 Y 缩放比例从 1 更改为 0。这提供了显示内容折叠到 header 中的动画。正如您从关键帧中看到的那样,我们交错了两个属性的动画,以便内容在完成缩放之前淡出。
在可见状态下,我们实质上是通过在相同的时间内将不透明度和 Y 缩放比例从 0 更改为 1 来反转折叠状态。
尝试将它们加载到您的控件中并在 Blend 中进行操作。这是一个很好的起点,因为我很快就把它们放在一起了。
您可以在此处找到有关使用 Blend 制作故事板的更多信息:https://blogs.msdn.microsoft.com/avtarsohi/2016/02/16/understand-storyboard-concept-in-xaml-using-blend-2015/