Wpf Design And Animation Lab
これはWPFプロジェクトであり、面白いデザインやアニメーションを作成・収集するためのものです。現在、数十のデモがあり、一部のデモには詳細な実装手順と原理を説明するブログ記事があります。
Design and Animation - dino.c - Blog園
これらのブログを通じて、クールなWPFアニメーションやデザインの実装方法、そしてWPFの技術的な詳細を学ぶことができます。
1. 実装済みのデザインとアニメーション
1.1 3つの方法で円弧進捗バーを実装

円弧進捗バーの実装方法は多数あります。PathとArcSegment、Arc、Ellipseの3つの方法を使うことで、さまざまなShapeの基本的な使い方を理解できます。
1.2 Rectangleのみで円柱形進捗バーを実装

円柱形進捗バーの実装は難しくありませんが、興味深いことに上の図はすべてRectangle(矩形)で構成されています。これは少し直感に反します。
まず、基本知識をおさらいしましょう。Rectangleは角丸の矩形を表示します。RadiusXとRadiusYで、矩形の角を丸める楕円のX軸半径とY軸半径をそれぞれ指定できます。
次の例では、RadiusX="50" RadiusY="20"のRectangleの角丸が、Width="100" Height="40"のEllipse(X軸半径50、Y軸半径20)と完全に重なっていることがわかります。
<Rectangle Height="100"
Width="100"
Fill="#FF7E9EC0"
Stroke="#FFFF0EC4"
StrokeThickness="5"
RadiusX="50"
RadiusY="20" />
<Ellipse HorizontalAlignment="Left"
VerticalAlignment="Top"
StrokeThickness="5"
Stroke="Yellow"
Fill="Red"
Width="100"
Height="40"
Opacity="0.5" />

上のRectangleを引き伸ばすと、円柱の基本的な形状になります。逆に押しつぶすと、円柱の断面になります。これらを半透明に設定すると、円柱形進捗バーの背景になります。

<Grid.Resources>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="#36a8e2" />
<Setter Property="RadiusX" Value="25" />
<Setter Property="RadiusY" Value="5" />
</Style>
</Grid.Resources>
<Rectangle Opacity="0.2" />
<Rectangle Height="10"
VerticalAlignment="Top"
Opacity="0.1" />
さらに半透明のグラデーションを追加し、もう一つの断面を追加すると、円柱形進捗バーが完成します。
1.3 虹色テキストとアニメーションを楽しむ
ItemsControlでテキストを分割して虹色テキストを実現するのは非常に面白い方法です。各文字に異なる変形やアニメーションを適用でき、さまざまな遊び方が可能です。まず、stringはコレクションであるため、ItemsControlのItemsSourceとして使用できます。ただし、XAMLに直接 ItemsSource="somestring"` と記述するとエラーになります。ContentControlでラップして次のように記述します。
<ContentControl Content="ItemsControl" >
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<ItemsControl ItemsSource="{TemplateBinding Content}" >
</ItemsControl>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
次に、ItemsControlのItemsPanelを設定してコンテンツを横方向に配置し、DataTemplateを設定して分割された文字をTextBlockに表示します。
<ItemsControl ItemsSource="{TemplateBinding Content}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
次に、各文字に異なる色を表示するために、Collectionクラスを実装し、XAML上でインスタンス化して使用する色を格納します。
<common:RepeatCollection x:Key="RepeatCollection">
<SolidColorBrush>#4a0e68</SolidColorBrush>
<SolidColorBrush>#b62223</SolidColorBrush>
<SolidColorBrush>#fdd70c</SolidColorBrush>
<SolidColorBrush>#f16704</SolidColorBrush>
<SolidColorBrush>#69982d</SolidColorBrush>
<SolidColorBrush>#0075a5</SolidColorBrush>
<SolidColorBrush>#0b0045</SolidColorBrush>
</common:RepeatCollection>
このRepeatCollectionのコードは以下の通りです。これは循環キューであり、Nextのgetterを呼び出すたびに次の要素を取得します(CircleCollectionの方が適切でしょうか?)。
public class RepeatCollection : Collection<object>
{
private int _offset;
public object Next
{
get
{
if (this.Count == 0)
return null;
var result = this[_offset];
_offset++;
if (_offset > this.Count - 1)
_offset = 0;
return result;
}
}
}
最後に、TextBlockのForegroundをコレクションのNextプロパティにバインドして、各TextBlockが異なる色を使用するようにします。
<TextBlock Foreground="{Binding Next, Source={StaticResource RepeatCollection}}" Text="{Binding}" />

上のコードを修正すると、虹色テキストのアニメーションを実現できます。

1.4 虹色ボタンを作成する
LinearGradientBrushをテキストに適用すると、テキストが虹色になります。2つのGradientStop間のColorが同じであればグラデーションは発生せず、Offsetが異なるとすぐに変化します。この手法を利用し、等幅フォントを使用することで、各文字の色が異なる虹色テキストを作成できます。
<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0.5" EndPoint="1,.5">
<GradientStop x:Name="G1" Offset="0" Color="#65b849" />
<GradientStop x:Name="G2" Offset=".166" Color="#65b849" />
<GradientStop x:Name="G3" Offset=".166" Color="#f7b423" />
<GradientStop x:Name="G4" Offset=".3333" Color="#f7b423" />
<GradientStop x:Name="G5" Offset="0.3333" Color="#f58122" />
<GradientStop x:Name="G6" Offset="0.5" Color="#f58122" />
<GradientStop x:Name="G7" Offset="0.5" Color=" #f8f8f8" />
<GradientStop x:Name="G8" Offset="0.5" Color=" #f8f8f8" />
<GradientStop x:Name="G9" Offset="0.50" Color="#de3a3c" />
<GradientStop x:Name="G10" Offset="0.666" Color="#de3a3c" />
<GradientStop x:Name="G11" Offset="0.666" Color="#943f96" />
<GradientStop x:Name="G12" Offset="0.8633" Color="#943f96" />
<GradientStop x:Name="G13" Offset="0.8633" Color="#009fd9" />
<GradientStop x:Name="G14" Offset="01" Color="#009fd9" />
</LinearGradientBrush>

MouseOverのStoryboard内でLinearGradientBrushの方向を制御します。方向を変更する方法は2つあります。1つはPointAnimationを使用してStartPointとEndPointを変更する方法、もう1つはDoubleAnimationを使用してLinearGradientBrush.RelativeTransformを直接変更する方法です。後者の書き方は以下の通りです。
<Storyboard>
<DoubleAnimation Storyboard.TargetName="textBlock"
Storyboard.TargetProperty="(TextBlock.Foreground).(Brush.RelativeTransform).(RotateTransform.Angle)"
To="90"
Duration="0:0:0.5">
<DoubleAnimation.EasingFunction>
<QuarticEase EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0.5" EndPoint="1,.5">
<LinearGradientBrush.RelativeTransform>
<RotateTransform Angle="0" CenterX="0.5" CenterY="0.5" />
</LinearGradientBrush.RelativeTransform>
実行時の効果は、すべての色が90度回転し、かつてのAppleのロゴの配色のように見えます。上のLinearGradientBrushでは、こっそりと2つの白色のGradientStop(G6とG7という名前のもの)を隠しており、それらのOffsetは両方とも0.5で中央に位置しています。ボタンのPressed状態では、DoubleAnimationを使用してそれらの前後のすべてのGradientStopのOffsetを0または1に設定し、すべての色を両端に押し出します。90度回転しているため、実際には上下に押し出されます。

1.5 任天堂Switchのローディングアニメーションを2つ実装


テキスト分割とTimeSpanIncreaserの方法を使用して、任天堂Switchで最もよく見られる2つのアニメーションを実装しました。
1.6 Shazzam Shader Editorを使用してLighten Effectを作成する
上のアニメーションでは、異なる明るさのGridを実現するためにLightenConverterクラスを使用しましたが、これはSolidColorBrushのみを処理できます。より多くの場面に適用できるように、次は自分でEffectを作成して同じLighten効果を実現します。

1.7 WPFでInner Shadowを実装する
WPFでは、通常DropShadowを使用して影効果を作成しますが、外側の影のみです。内側の影(Inner Shadow)も不可能ではありませんが、少し回りくどいです。内側の影を実装する方法はいくつかありますが、私が最も好きなのは、別の要素のVisualBrushをOpacityMaskとして使用する方法です。
<Grid Width="100"
Height="100"
Margin="10">
<Rectangle x:Name="Rectangle2"
Fill="White"
RadiusX="8"
RadiusY="8" />
<Border Margin="0">
<Border.Effect>
<DropShadowEffect BlurRadius="8" ShadowDepth="0" />
</Border.Effect>
<ContentControl HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="OpacityMask" />
</Border>
<Grid.OpacityMask>
<VisualBrush Stretch="None" Visual="{Binding ElementName=Rectangle2}" />
</Grid.OpacityMask>
</Grid>
しかし、これで作成される影はあまり太くなりません。より大きく太い内側の影が必要な場合は、負のMarginとそれと同じ太さのBorderThicknessを組み合わせて実現できます。OpacityMaskの方法を例にとると、次のコードで太くて大きな内側の影を作成できます。
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
ShadowElement.Margin = new Thickness(-e.NewValue);
ShadowElement.BorderThickness = new Thickness(e.NewValue);
(ShadowElement.Effect as DropShadowEffect).BlurRadius = e.NewValue * 2;
}

1.8 OpacityMaskでUWPのText Shimmerアニメーションを模倣する

UWPのWindows Composition Samplesには、Composition Lightの使用方法を示すためのText Shimmerアニメーションがあります。このアニメーションは単純で、PointLightが左から右へテキストの行をスキャンするものです。WPFにはComposition Lightがありませんが、この単純なアニメーションを再現することは可能です。OpacityMaskで模倣するだけです。
RadialGradientBrush は円形のグラデーションブラシを表します。ここでは3つのプロパティに注目します。
RadiusX/RadiusY: 円形の水平/垂直半径。 Center: 円形の最も外側の中心。 GradientOrigin: グラデーションが始まる2次元の焦点の位置。
これらの3つのプロパティの役割は下図を参照してください。

RadialGradientBrushをOpacityMaskとして使用し、TextBlockを中心点から外側に向かって徐々に透明にします。
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="SegoeUI"
FontSize="100"
FontWeight="Thin"
Foreground="DimGray"
Text="Text Shimmer">
<TextBlock.OpacityMask>
<RadialGradientBrush x:Name="Brush" Center=".5,.5" GradientOrigin=".5,.5" RadiusX=".43" RadiusY="2">
<GradientStop Color="Black" />
<GradientStop Offset=".5" Color="#6000" />
<GradientStop Offset="1" Color="#2000" />
</RadialGradientBrush>
</TextBlock.OpacityMask>
</TextBlock>
次に、CenterとGradientOriginにPointAnimationを適用してOpacityMaskを水平移動させ、PointLightがスキャンする効果を模倣します。
<PointAnimation RepeatBehavior="Forever"
Storyboard.TargetName="Brush"
Storyboard.TargetProperty="Center"
From="-2,.5"
To="3,.5"
Duration="0:0:3.3" />
<PointAnimation RepeatBehavior="Forever"
Storyboard.TargetName="Brush"
Storyboard.TargetProperty="GradientOrigin"
From="-2,.5"
To="3,.5"
Duration="0:0:3.3" />
1.9 CSS3で実装されたボタンをパクる

CSS3で実装されたボタンをパクり、ついでにCSS3に慣れ親しみます。
1.10 Effectで線の光と影の効果を実現

この効果を実現するために、以下の知識とテクニックを使用しました。
- Segoe Fluentアイコンフォント
- BlendでのPathの作成
- Pathの長さの計算
- Pathの境界線アニメーション
- VisualStudioのデザイン時データのサポート
- カスタムEffect
2. ライセンス
このプロジェクトはMITライセンスの下で公開されています。
3. UWPバージョン
また、UWPアニメーションを試すための別のプロジェクトもあります。
https://github.com/DinoChan/uwp_design_and_animation_lab

GitHubからの転載
作者: dino.c
リポジトリ: https://github.com/DinoChan/wpf_design_and_animation_lab