Shu*_*ahu 24 c# xaml windows-phone-8.1 uwp windows-phone-silverlight
我已经在Windows Phone 8.1 Silverlight App和UWP中创建了一个椭圆,我想用动画波填充它,为此,我正在遵循这个解决方案
但它适用于WPF,所以我无法使用像"Visual Brush"这样的控件.
我想用类似于此的波填充椭圆(忽略图像中的50%) -
这是我的eliipse
<Ellipse Name="WaveEllipse" Grid.Column="1" Grid.Row="0" VerticalAlignment="Top"
Stroke="{StaticResource PhoneAccentBrush}"
StrokeThickness="4"
Width="225"
Height="225">
</Ellipse>
Run Code Online (Sandbox Code Playgroud)
视觉刷上的任何替代品?主要是我想在Windows Phone 8.1 Silverlight中实现它,但是如果它在WP平台上不可用,我将切换到UWP
Jus*_* XL 81
在给你代码之前,看看下面这个动画gif,试着理解如何创建这个动画.
有道理,对吧?我们需要做的就是创建一个这样的形状,为其偏移X(无限)和Y(水位)设置动画,最后用椭圆剪切它.
首先,您需要使用Adobe Illustrator或类似工具来创建此形状.在AI中,有一个Zig Zag效果(见下面的截图),这是完美的.你只需要确保起点与结束点的位置相同,所以当你重复动画时,它会觉得它永远不会结束.
UWP中目前缺少的是能够剪切UIElement非矩形形状,因此我们必须将其导出为png(否则我们将其导出为svg并用于Path显示它).
同样出于同样的原因,剪辑部分需要大量的工作.就像Jet Chopper的答案一样,那就是大量的代码surfaceBrush!更不用说您还需要手动处理设备丢失和应用程序生命周期.
值得庆幸的是,在创建者更新(即15063)中,有一个新的API被称为通过图像uri LoadedImageSurface创建一个CompositionSurfaceBrush带有几行代码的UI.在我下面的代码示例中,您将看到我使用它,这意味着,如果您想支持旧版本的Windows 10,则需要将其替换为Jet的答案中的内容.
我们的想法是创建一个UserControl,它调用WaveProgressControl封装所有动画逻辑并公开一个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>
Run Code Online (Sandbox Code Playgroud)
该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()
{
// Note LoadedImageSurface is only available in 15063 onward.
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(); // CompositionSurfaceBrush
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);
}
}
Run Code Online (Sandbox Code Playgroud)
该 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>
Run Code Online (Sandbox Code Playgroud)
我已将所有内容都放入此示例项目中,下面是一个现场演示.请享用!:)
Jet*_*per 12
这是UWP样本.您可以根据需要进行调整:
<Canvas>
<Ellipse x:Name="Ellipse" Width="256" Height="256" Fill="DarkViolet" Stroke="DeepSkyBlue" StrokeThickness="8"/>
<Border x:Name="VisualBorder" Opacity="0.5"/>
</Canvas>
Run Code Online (Sandbox Code Playgroud)
和代码背后:
private async void CreateVisuals()
{
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var bitmap = await CanvasBitmap.LoadAsync(CanvasDevice.GetSharedDevice(),
new Uri("ms-appx:///Assets/Wave-PNG-Transparent-Picture.png"));
var drawingSurface =
CanvasComposition.CreateCompositionGraphicsDevice(compositor, CanvasDevice.GetSharedDevice())
.CreateDrawingSurface(bitmap.Size,
DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawImage(bitmap);
}
var surfaceBrush = compositor.CreateSurfaceBrush(drawingSurface);
surfaceBrush.Stretch = CompositionStretch.None;
var maskedBrush = compositor.CreateMaskBrush();
maskedBrush.Mask = Ellipse.GetAlphaMask();
maskedBrush.Source = surfaceBrush;
var sprite = compositor.CreateSpriteVisual();
sprite.Size = new Vector2((float)Ellipse.Width, (float)Ellipse.Height);
sprite.Brush = maskedBrush;
sprite.CenterPoint = new Vector3(sprite.Size / 2, 0);
sprite.Scale = new Vector3(0.9f);
ElementCompositionPreview.SetElementChildVisual(VisualBorder, sprite);
var offsetAnimation = compositor.CreateScalarKeyFrameAnimation();
offsetAnimation.InsertKeyFrame(0, 0);
offsetAnimation.InsertKeyFrame(1, 256, compositor.CreateLinearEasingFunction());
offsetAnimation.Duration = TimeSpan.FromMilliseconds(1000);
offsetAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
surfaceBrush.StartAnimation("Offset.X", offsetAnimation);
}
}
Run Code Online (Sandbox Code Playgroud)
这是它的样子: