使用 VisualStateManager 对按钮的 ScaleTransform 进行动画处理
Animate ScaleTransform of a Button using VisualStateManager
我为包含网格和内容控件的按钮创建了控件模板。我想要做的是:按下按钮时,按钮的比例应设置为 0.5,当按钮离开按下状态时,按钮的比例应设置为 1.0。
在我当前的解决方案中,如果按下按钮,缩放 = 0.5 的动画效果很好。但是只要我松开按钮,动画就不会慢慢缩小到比例 1。而是立即按比例 1。
我的实现是这样的:
<Style TargetType="Button" x:Name="MyButtonStyle">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="{TemplateBinding Background}" x:Name="buttonLayoutRoot">
<Grid.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="Pressed" GeneratedDuration="0:0:2.5">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)"
To="0.5" Duration="0:0:2.5"/>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)"
To="0.5" Duration="0:0:2.5"/>
</Storyboard>
</VisualTransition>
<VisualTransition To="Normal" GeneratedDuration="0:0:2.5">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)"
To="1.0" Duration="0:0:2.5"/>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)"
To="1.0" Duration="0:0:2.5"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl
x:Name="ButtonContent"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}">
</ContentControl>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我还尝试将动画放入视觉状态 "normal" 和 "pressed" 而没有任何过渡。但结果是一样的。当不再按下按钮时,它只是快速回到 scale = 1。
我正在为 windows phone 8.0 silverlight 编程。
希望大家能帮帮我。
谢谢,凯文
好的,那么看看你的东西……你在如何显式设置 RenderTransform 方面遇到了另一个问题。让那个东西保持打开状态,因为我们正在动态地与它交互(看看我的例子中的 Grid.RenderTransform
)。您还需要在 buttonLayoutRoot 上设置一个 RenderTransformOrigin
,这样它也知道您要返回什么。
虽然我现在没有时间向您介绍整个解释,因为我有自己的工作任务要做,但这里有一个通用的按钮样式,您可以参考我做了一段时间回来做你想要的。注意差异。我在这里删除了我的大部分其他自定义废话,所以不应该有任何资源冲突或任何东西,但你应该很快就会注意到差异。
<Style x:Key="StandardButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Blue" />
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="Container"
RenderTransformOrigin="0.5,0.5" Cursor="{TemplateBinding Cursor}">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform />
</TransformGroup>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="MouseOver"
GeneratedDuration="0:0:0.1"
To="Pressed">
<VisualTransition.GeneratedEasingFunction>
<ExponentialEase EasingMode="EaseIn" Exponent="-2" />
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
<VisualTransition From="Pressed"
GeneratedDuration="0:0:0.1"
To="MouseOver">
<VisualTransition.GeneratedEasingFunction>
<ExponentialEase EasingMode="EaseOut" Exponent="0" />
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="MouseOverState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="PressedState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Container" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0.01" Value="1.05" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Container" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0.01" Value="1.05" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="DisabledState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="FocusedState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="BaseBackground"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"/>
<Border x:Name="MouseOverState"
BorderThickness="{TemplateBinding BorderThickness}"
Visibility="Collapsed"/>
<Border x:Name="PressedState"
BorderThickness="{TemplateBinding BorderThickness}"
Visibility="Collapsed"/>
<Border x:Name="FocusedState"
Background="{TemplateBinding Background}"
Visibility="Collapsed"/>
<ContentControl x:Name="contentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
IsTabStop="False"/>
<Border x:Name="DisabledState"
Background="White"
Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
希望这对您有所帮助,干杯! :)
诀窍是,只定义您感兴趣的视觉状态。在这种情况下,您只对 "pressed" 和 "normal" 感兴趣,所以只定义它们。这是一个例子:
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter x:Name="LayoutRoot" RenderTransformOrigin="0.5 0.5">
<ContentPresenter.RenderTransform>
<ScaleTransform/>
</ContentPresenter.RenderTransform>
<ContentPresenter.Foreground>
<SolidColorBrush Color="White"/>
</ContentPresenter.Foreground>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard Duration="0:0:0.5">
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleX)"
To="1" Duration="0:0:0.5"/>
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleY)"
To="1" Duration="0:0:0.5"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard Duration="0:0:0.5">
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleX)"
To="0.8" Duration="0:0:0.5"/>
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleY)"
To="0.8" Duration="0:0:0.5"/>
<ColorAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.Foreground).(SolidColorBrush.Color)"
To="Red" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</ControlTemplate>
</Button.Template>
只要视觉状态管理器改变状态,动画就会重置,除非新状态没有在您的模板中声明。 F.e。如果您只定义 "pressed" 状态,按钮将保持在 0.8 比例。仅当您还声明 "Normal" 时,动画才会重置。
我为包含网格和内容控件的按钮创建了控件模板。我想要做的是:按下按钮时,按钮的比例应设置为 0.5,当按钮离开按下状态时,按钮的比例应设置为 1.0。
在我当前的解决方案中,如果按下按钮,缩放 = 0.5 的动画效果很好。但是只要我松开按钮,动画就不会慢慢缩小到比例 1。而是立即按比例 1。
我的实现是这样的:
<Style TargetType="Button" x:Name="MyButtonStyle">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="{TemplateBinding Background}" x:Name="buttonLayoutRoot">
<Grid.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="Pressed" GeneratedDuration="0:0:2.5">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)"
To="0.5" Duration="0:0:2.5"/>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)"
To="0.5" Duration="0:0:2.5"/>
</Storyboard>
</VisualTransition>
<VisualTransition To="Normal" GeneratedDuration="0:0:2.5">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)"
To="1.0" Duration="0:0:2.5"/>
<DoubleAnimation
Storyboard.TargetName="buttonLayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)"
To="1.0" Duration="0:0:2.5"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl
x:Name="ButtonContent"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}">
</ContentControl>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我还尝试将动画放入视觉状态 "normal" 和 "pressed" 而没有任何过渡。但结果是一样的。当不再按下按钮时,它只是快速回到 scale = 1。
我正在为 windows phone 8.0 silverlight 编程。
希望大家能帮帮我。
谢谢,凯文
好的,那么看看你的东西……你在如何显式设置 RenderTransform 方面遇到了另一个问题。让那个东西保持打开状态,因为我们正在动态地与它交互(看看我的例子中的 Grid.RenderTransform
)。您还需要在 buttonLayoutRoot 上设置一个 RenderTransformOrigin
,这样它也知道您要返回什么。
虽然我现在没有时间向您介绍整个解释,因为我有自己的工作任务要做,但这里有一个通用的按钮样式,您可以参考我做了一段时间回来做你想要的。注意差异。我在这里删除了我的大部分其他自定义废话,所以不应该有任何资源冲突或任何东西,但你应该很快就会注意到差异。
<Style x:Key="StandardButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Blue" />
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="Container"
RenderTransformOrigin="0.5,0.5" Cursor="{TemplateBinding Cursor}">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform />
</TransformGroup>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="MouseOver"
GeneratedDuration="0:0:0.1"
To="Pressed">
<VisualTransition.GeneratedEasingFunction>
<ExponentialEase EasingMode="EaseIn" Exponent="-2" />
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
<VisualTransition From="Pressed"
GeneratedDuration="0:0:0.1"
To="MouseOver">
<VisualTransition.GeneratedEasingFunction>
<ExponentialEase EasingMode="EaseOut" Exponent="0" />
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="MouseOverState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="PressedState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Container" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0.01" Value="1.05" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Container" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0.01" Value="1.05" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="DisabledState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="FocusedState" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="BaseBackground"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"/>
<Border x:Name="MouseOverState"
BorderThickness="{TemplateBinding BorderThickness}"
Visibility="Collapsed"/>
<Border x:Name="PressedState"
BorderThickness="{TemplateBinding BorderThickness}"
Visibility="Collapsed"/>
<Border x:Name="FocusedState"
Background="{TemplateBinding Background}"
Visibility="Collapsed"/>
<ContentControl x:Name="contentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
IsTabStop="False"/>
<Border x:Name="DisabledState"
Background="White"
Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
希望这对您有所帮助,干杯! :)
诀窍是,只定义您感兴趣的视觉状态。在这种情况下,您只对 "pressed" 和 "normal" 感兴趣,所以只定义它们。这是一个例子:
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter x:Name="LayoutRoot" RenderTransformOrigin="0.5 0.5">
<ContentPresenter.RenderTransform>
<ScaleTransform/>
</ContentPresenter.RenderTransform>
<ContentPresenter.Foreground>
<SolidColorBrush Color="White"/>
</ContentPresenter.Foreground>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard Duration="0:0:0.5">
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleX)"
To="1" Duration="0:0:0.5"/>
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleY)"
To="1" Duration="0:0:0.5"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard Duration="0:0:0.5">
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleX)"
To="0.8" Duration="0:0:0.5"/>
<DoubleAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.RenderTransform).(ScaleTransform.ScaleY)"
To="0.8" Duration="0:0:0.5"/>
<ColorAnimation Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(ContentPresenter.Foreground).(SolidColorBrush.Color)"
To="Red" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</ControlTemplate>
</Button.Template>
只要视觉状态管理器改变状态,动画就会重置,除非新状态没有在您的模板中声明。 F.e。如果您只定义 "pressed" 状态,按钮将保持在 0.8 比例。仅当您还声明 "Normal" 时,动画才会重置。