- A+
写了两个 Switch 的加载动画,第一个是 Swtich 最常见那个 Loading 动画:
其中拆分文字用到了 之前一篇文章 里提到的用 ItemsControl 拆分的方案,文字逐个反转的动画也用了那篇文章里提到的 TimeSpanIncreaser
来控制 BeginTime:
<Storyboard BeginTime="{Binding Next, Source={StaticResource TimeSpanIncreaser}}" RepeatBehavior="Forever"> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="TextElement" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" Duration="0:0:4"> <LinearDoubleKeyFrame KeyTime="0:0:0.4" Value="-1" /> <LinearDoubleKeyFrame KeyTime="0:0:0.6" Value="1" /> <LinearDoubleKeyFrame KeyTime="0:0:0.8" Value="-1" /> </DoubleAnimationUsingKeyFrames> </Storyboard>
另一个是 eShop 的加载动画,看起来简单,实现过程反而更有趣。
要实现这个动画,第一步要先把每行都拆分成一个独立的部分,然后还是使用 TimeSpanIncreaser
控制每个部分的开始动画的时间:
<local:NintendoEShopLoadingRow Delay="{Binding Next, Source={StaticResource TimeSpanIncreaser}}" /> <local:NintendoEShopLoadingRow Grid.Row="1" Delay="{Binding Next, Source={StaticResource TimeSpanIncreaser}}" /> <local:NintendoEShopLoadingRow Grid.Row="2" Delay="{Binding Next, Source={StaticResource TimeSpanIncreaser}}" /> <local:NintendoEShopLoadingRow Grid.Row="3" Delay="{Binding Next, Source={StaticResource TimeSpanIncreaser}}" /> <local:NintendoEShopLoadingRow Grid.Row="4" Delay="{Binding Next, Source={StaticResource TimeSpanIncreaser}}" /> <local:NintendoEShopLoadingRow Grid.Row="5" Delay="{Binding Next, Source={StaticResource TimeSpanIncreaser}}" />
然后实现 NintendoEShopLoadingRow
,先在里面放上四个颜色由浅到深的 Grid。为了不写死颜色,我做了个 LightenConverter
,具体用法如下:
<Grid Background="{Binding Foreground, ElementName=Row, Converter={StaticResource LightenConverter}, ConverterParameter=.8}" /> <Grid Background="{Binding Foreground, ElementName=Row, Converter={StaticResource LightenConverter}, ConverterParameter=.6}" /> <Grid Background="{Binding Foreground, ElementName=Row, Converter={StaticResource LightenConverter}, ConverterParameter=.4}" /> <Grid Background="{Binding Foreground, ElementName=Row}" />
LightenConverter
的代码如下,先实现一个 HslColor
类,HSL即色相、饱和度、亮度(英语:Hue, Saturation, Lightness)。LightenConverter
将原本的 SolidColorBrush 中的 Color 转换成 HslColor,然后修改亮度后再转换回来:
public class LightenConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var brush = value as SolidColorBrush; if (brush == null) return value; var amount =System.Convert.ToDouble(parameter); return new SolidColorBrush(new HslColor(brush.Color).Lighten(amount).ToRgb()); } public HslColor Lighten(HslColor source, double amount) { return new HslColor(source.h, source.s, source.l + (1 - source.l) * amount, source.a); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); }
这样就实现了 4 个 Grid 使用同一个颜色,但亮度不同。
最后要让这四个 Grid 动起来(其实只是动前面三个)。虽然说”动起来“,但并不是做移动的动画,而是用 ScaleTransform 做拉伸,同样是做 ScaleX 从 1 到 0 的动画,如果 RenderTransformOrigin="0,0.5"
就是以左边界为中心,即从右往左缩小;反之 RenderTransformOrigin="1,0.5"
就是从左往右缩小。通过设置 RenderTransformOrigin
实现了各层往不同的方向缩小,实现了左右往返的动画:
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="L1" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"> <LinearDoubleKeyFrame KeyTime="00:00:1" Value="0" /> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="L2" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"> <LinearDoubleKeyFrame KeyTime="00:00:1" Value="1" /> <LinearDoubleKeyFrame KeyTime="00:00:2" Value="0" /> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="L3" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"> <LinearDoubleKeyFrame KeyTime="00:00:2" Value="1" /> <LinearDoubleKeyFrame KeyTime="00:00:3" Value="0" /> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="L1" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"> <LinearDoubleKeyFrame KeyTime="00:00:3" Value="0" /> <LinearDoubleKeyFrame KeyTime="00:00:4" Value="1" /> </DoubleAnimationUsingKeyFrames>
可惜的是,这个动画对 WPF 来说有些勉强,偶尔会有卡顿的现象。反正只是玩玩,正式产品不要在这么大的元素上做动画。