如何在WPF中使用DoubleAnimation实现FontStretch属性动画?
如何为FontStretch属性创建动画?
你这段代码的问题很明显——FontStretch是FontStretch类型,不是Double,所以用DoubleAnimation直接动画它肯定会失效,WPF根本没法把Double值转换成FontStretch。下面给你两种实用的解决方案,选哪种看你的需求:
方案一:用ObjectAnimationUsingKeyFrames实现平滑过渡(推荐)
这种方法不用写额外的C#代码,直接在XAML里搞定,而且能实现平滑的字体拉伸效果。核心是利用WPF对FontStretch类型的插值支持,用LinearObjectKeyFrame来做关键帧动画:
<Style TargetType="TextBlock" x:Key="TextBlockStyle"> <!-- 默认字体拉伸为Normal --> <Setter Property="FontStretch" Value="{x:Static FontStretches.Normal}"/> <Style.Triggers> <!-- 鼠标进入时,0.3秒内从Normal变为UltraCondensed --> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="FontStretch" Duration="0:0:0.3"> <LinearObjectKeyFrame KeyTime="0:0:0" Value="{x:Static FontStretches.Normal}"/> <LinearObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static FontStretches.UltraCondensed}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> <!-- 鼠标离开时,还原回Normal --> <EventTrigger RoutedEvent="MouseLeave"> <BeginStoryboard> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="FontStretch" Duration="0:0:0.3"> <LinearObjectKeyFrame KeyTime="0:0:0" Value="{x:Static FontStretches.UltraCondensed}"/> <LinearObjectKeyFrame KeyTime="0:0:0.3" Value="{x:Static FontStretches.Normal}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Style.Triggers> </Style>
另外提一句:你原来的EventTrigger写的是Button.MouseEnter,但这个Style是给TextBlock用的,改成MouseEnter就够了,WPF会自动匹配目标控件的事件。
方案二:用DoubleAnimation+转换器(自定义数值场景)
如果需要更精细控制拉伸的数值(比如不是用预定义的UltraCondensed,而是自定义某个拉伸值),可以用DoubleAnimation配合转换器。步骤如下:
第一步:创建转换器类
在你的项目里加一个C#类,把Double值转换成FontStretch:
using System; using System.Globalization; using System.Windows; using System.Windows.Data; namespace YourNamespace { public class DoubleToFontStretchConverter : IValueConverter { // 把Double转换成FontStretch public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is double numericValue) { // OpenType拉伸值范围是1-1000,Normal对应100,UltraCondensed对应50 return FontStretch.FromOpenTypeStretch((int)numericValue); } return FontStretches.Normal; } // 把FontStretch转换成Double(动画需要双向绑定) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value is FontStretch stretch) { return stretch.NumericValue; } return 100.0; } } }
第二步:在XAML里使用转换器
用TextBlock的Tag属性作为中间值,通过转换器绑定到FontStretch,然后动画Tag的Double值:
<Window.Resources> <!-- 引用转换器 --> <local:DoubleToFontStretchConverter x:Key="DoubleToFontStretchConverter"/> <Style TargetType="TextBlock" x:Key="TextBlockStyle"> <Setter Property="FontStretch" Value="{Binding RelativeSource={RelativeSource Self}, Path=Tag, Converter={StaticResource DoubleToFontStretchConverter}}"/> <!-- 默认Tag值为100(对应Normal) --> <Setter Property="Tag" Value="100"/> <Style.Triggers> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Tag" From="100" To="50" <!-- 对应UltraCondensed --> Duration="0:0:0.3"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeave"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Tag" From="50" To="100" Duration="0:0:0.3"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Style.Triggers> </Style> </Window.Resources>
两种方案里,第一种更简单直接,适合大多数场景;第二种适合需要自定义拉伸程度的情况,比如动画到一个预定义值之外的拉伸效果。
内容的提问来源于stack exchange,提问作者Imathie
相关产品推荐
相关产品推荐

