在提供代码之前,请观看下面的动画 gif,尝试理解如何创建此动画。
有意义吧?我们需要做的就是创建这样一个形状,无限地对其进行X轴(水平方向)和Y轴(水位高度)的偏移动画,并最后将其剪切为椭圆形状。
因此,首先需要使用Adobe Illustrator或类似工具创建此形状。在AI中,有一个名为Zig Zag效果(请参见下面的截图),非常适合此用途。只需确保起点与结束点相同,以便在重复动画时,它会感觉像是永无止境的。
目前在UWP中缺少的是使用非矩形形状裁剪UIElement
的能力,因此在此我们需要将其导出为png(否则我们将其导出为svg并使用Path
显示它)。
同样出于这个原因,裁剪部分需要大量的工作。就像Jet Chopper所回答的那样,为了得到一个surfaceBrush
,需要写很多代码!更不用说,您还需要手动处理设备丢失和应用程序生命周期。
值得庆幸的是,在创作者更新(即15063)中,有一个名为LoadedImageSurface
的新API,可以通过图像URI创建一个CompositionSurfaceBrush
,只需几行代码。在我下面的代码示例中,您将看到我使用了此功能,这意味着,如果要支持Windows 10的旧版本,则需要将其替换为Jet答案中的内容。
代码
想法是创建一个名为WaveProgressControl
的UserControl,该UserControl封装了所有动画逻辑,并公开了一个称为Percent
的依赖属性,该属性控制水位高度。
WaveProgressControl
控件 - XAML
<UserControl x:Class="WaveProgressControlRepo.WaveProgressControl"
Height="160"
Width="160">
<Grid x:Name="Root">
<Ellipse x:Name="ClippedImageContainer"
Fill="White"
Margin="6" />
<Ellipse x:Name="CircleBorder"
Stroke="#FF0289CD"
StrokeThickness="3" />
<TextBlock Foreground="#FF0289CD"
FontSize="36"
FontWeight="SemiBold"
TextAlignment="Right"
VerticalAlignment="Center"
Width="83"
Margin="0,0,12,0">
<Run Text="{x:Bind Percent, Mode=OneWay}" />
<Run Text="%"
FontSize="22" />
</TextBlock>
</Grid>
</UserControl>
WaveProgressControl
控件 - 代码后台
private readonly Compositor _compositor;
private readonly CompositionPropertySet _percentPropertySet;
public WaveProgressControl()
{
InitializeComponent();
_compositor = Window.Current.Compositor;
_percentPropertySet = _compositor.CreatePropertySet();
_percentPropertySet.InsertScalar("Value", 0.0f);
Loaded += OnLoaded;
}
public double Percent
{
get => (double)GetValue(PercentProperty);
set => SetValue(PercentProperty, value);
}
public static readonly DependencyProperty PercentProperty =
DependencyProperty.Register("Percent", typeof(double), typeof(WaveProgressControl),
new PropertyMetadata(0.0d, (s, e) =>
{
var self = (WaveProgressControl)s;
var propertySet = self._percentPropertySet;
propertySet.InsertScalar("Value", Convert.ToSingle(e.NewValue) / 100);
}));
private void OnLoaded(object sender, RoutedEventArgs e)
{
CompositionSurfaceBrush imageSurfaceBrush;
SetupClippedWaveImage();
SetupEndlessWaveAnimationOnXAxis();
SetupExpressionAnimationOnYAxisBasedOnPercentValue();
void SetupClippedWaveImage()
{
var imageSurface = LoadedImageSurface.StartLoadFromUri(new Uri(BaseUri, "/Assets/wave.png"));
imageSurfaceBrush = _compositor.CreateSurfaceBrush(imageSurface);
imageSurfaceBrush.Stretch = CompositionStretch.None;
imageSurfaceBrush.Offset = new Vector2(120, 248);
var maskBrush = _compositor.CreateMaskBrush();
var maskSurfaceBrush = ClippedImageContainer.GetAlphaMask();
maskBrush.Mask = maskSurfaceBrush;
maskBrush.Source = imageSurfaceBrush;
var imageVisual = _compositor.CreateSpriteVisual();
imageVisual.RelativeSizeAdjustment = Vector2.One;
ElementCompositionPreview.SetElementChildVisual(ClippedImageContainer, imageVisual);
imageVisual.Brush = maskBrush;
}
void SetupEndlessWaveAnimationOnXAxis()
{
var waveOffsetXAnimation = _compositor.CreateScalarKeyFrameAnimation();
waveOffsetXAnimation.InsertKeyFrame(1.0f, -80.0f, _compositor.CreateLinearEasingFunction());
waveOffsetXAnimation.Duration = TimeSpan.FromSeconds(1);
waveOffsetXAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
imageSurfaceBrush.StartAnimation("Offset.X", waveOffsetXAnimation);
}
void SetupExpressionAnimationOnYAxisBasedOnPercentValue()
{
var waveOffsetYExpressionAnimation = _compositor.CreateExpressionAnimation("Lerp(248.0f, 120.0f, Percent.Value)");
waveOffsetYExpressionAnimation.SetReferenceParameter("Percent", _percentPropertySet);
imageSurfaceBrush.StartAnimation("Offset.Y", waveOffsetYExpressionAnimation);
}
}
主页面 MainPage
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:WaveProgressControl x:Name="WaveProgressControl" />
<Slider Grid.Row="1"
Margin="24"
Value="{x:Bind WaveProgressControl.Percent, Mode=TwoWay}" />
</Grid>
我已经将所有东西都放入了这个示例项目中,下面是一个实时演示。享受吧! :)
imageSurfaceBrush.Offset = new Vector2(120, 248);
,你能告诉我为什么要使用120,248
吗? - lindexi248
个单位并向右推120
个单位。 - Justin XL