Windows Phone 8.1 SilverlightアプリとUWPの両方で楕円を作成し、アニメーションウェーブで塗りつぶしたかった。この目的のために、この solution
しかし、これはWPF向けであるため、「ビジュアルブラシ」などのコントロールを使用できません。
これに似た波で楕円を塗りたかった(画像の50%を無視)-
そして、ここに私のeliipseです
<Ellipse Name="WaveEllipse" Grid.Column="1" Grid.Row="0" VerticalAlignment="Top"
Stroke="{StaticResource PhoneAccentBrush}"
StrokeThickness="4"
Width="225"
Height="225">
</Ellipse>
視覚ブラシの代替品はありますか?主にWindows Phone 8.1 Silverlightに実装したかったのですが、WPプラットフォームで利用できない場合はUWPに切り替えます
コードを提供する前に、このアニメーションgifを見て、このアニメーションの作成方法を理解してください。
理にかなっていますよね?必要なのは、このような形状を作成し、オフセットX(endlessly)およびY(water level)をアニメートし、最後に楕円でクリップするだけです。
そのため、最初にAdobe Illustratorまたは同様のツールを使用してこの形状を作成する必要があります。 [〜#〜] ai [〜#〜]には、ジグザグ効果があります(下のスクリーンショットを参照)この。開始点が終了点と同じ位置にあることを確認するだけでよいので、アニメーションを繰り返すと、終了しないように感じるでしょう。
現在UWPに欠けているのは、UIElement
を長方形以外の形状でクリップする機能です。したがって、ここではこれをpngとしてエクスポートする必要があります(そうでない場合はsvgそしてPath
を使用して表示します)。
また同じ理由で、クリッピング部分には多くの作業が必要です。 Jet Chopperの答えのように、それはsurfaceBrush
を取得するための大量のコードです!デバイスの紛失やアプリのライフサイクルも手動で処理する必要があることは言うまでもありません。
ありがたいことに、Creators Update(つまり15063)には、数行のコードでイメージuriによってLoadedImageSurface
を作成するCompositionSurfaceBrush
という新しいAPIがあります。以下の私のコード例では、これを使用していることがわかります。つまり、Windows 10の古いバージョンをサポートする場合は、Jetの答えにあるものに置き換える必要があります。
アイデアは、すべてのアニメーションロジックをカプセル化し、を制御するWaveProgressControl
という依存関係プロパティを公開するPercent
というUserControlを作成することです。水位。
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()
{
// 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);
}
}
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>
これにすべてを入れました サンプルプロジェクト 以下はライブデモです。楽しい! :)
UWPサンプルを次に示します。必要に応じて調整できます。
<Canvas>
<Ellipse x:Name="Ellipse" Width="256" Height="256" Fill="DarkViolet" Stroke="DeepSkyBlue" StrokeThickness="8"/>
<Border x:Name="VisualBorder" Opacity="0.5"/>
</Canvas>
そしてコードビハインド:
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);
}
}
以下にその様子を示します。
私は簡単な解決策を使用してこれを達成しました:
Wave2.pngは、より長くするために拡張されています(コピーして画像を貼り付け、最初の画像の最後に追加します)。
ソリューションはWP8 /ストアアプリ/ UWP/Silverlightで動作します
<Border
Background="White"
VerticalAlignment="Center"
HorizontalAlignment="Center"
CornerRadius="10000"
BorderBrush="Black"
BorderThickness="5">
<Grid>
<Ellipse
x:Name="ellipse"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Height="200"
Width="200">
<Ellipse.Fill>
<ImageBrush
x:Name="WaveImage"
Stretch="None"
ImageSource="wave2.png">
<ImageBrush.Transform>
<CompositeTransform
TranslateY="200"
TranslateX="299" />
</ImageBrush.Transform>
</ImageBrush>
</Ellipse.Fill>
</Ellipse>
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="HUJ" />
</Grid>
</Border>
そして、ここにアニメーションコードがあります。
<Storyboard
x:Name="AnimateWave">
<DoubleAnimationUsingKeyFrames
RepeatBehavior="Forever"
EnableDependentAnimation="True"
Storyboard.TargetProperty="(Shape.Fill).(Brush.Transform).(CompositeTransform.TranslateX)"
Storyboard.TargetName="ellipse">
<EasingDoubleKeyFrame
KeyTime="0:0:5"
Value="-299" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>