UWP アプリに Fluent Design System を実装する方法

この記事は [Microsoft Student Partners Japan Advent Calendar 2017](https://qiita.com/advent-calendar/2017/mspjp) の20日目の記事です。

本記事では、UWP アプリに Fluent Design System を実装する方法について、簡単に紹介します。


# Fluent Design System とは
Fluent Design System は、Windows 10 Fall Creators Update で導入されたアプリケーションの UI に関するコンセプトです。このコンセプトを実現するために、UWP には以下の機能が追加されています。

- アクリル素材（Acrylic material）
- 接続型アニメーション（Connected animation）
- 視差（Parallax）
- 表示（Reveal highlight）

これらの機能によって、次の動画で紹介されているような画面効果をもつ UWP アプリを作成することができます。
動画：[Fluent Design features for Fall Creators Update | One Dev Minute | Channel 9](https://channel9.msdn.com/Blogs/One-Dev-Minute/Fluent-Design-features-for-Fall-Creators-Update?ocid=player)

これから、上記4つの機能を UWP アプリに実装する方法について説明していきます。


# 開発環境
Fluent Design System の機能を実装する UWP アプリの開発には、以下の環境が必要です。

- Visual Studio 2017 Update 4 (15.4) 以降
- Windows 10 Fall Creators Update (10.0.16299.0) 以降

また、UWP アプリのプロジェクトを作成するときは、ターゲットバージョンと最小バージョンを Windows 10 Fall Creators Update（10.0; ビルド 16299) 以降に設定します。

<img width="600" alt="pre.png" src="https://qiita-image-store.s3.amazonaws.com/0/75597/ddb18916-dad0-ff83-00be-16fdb1b10213.png">




# アクリル素材（Acrylic material）
アクリル素材（Acrylic material）は、半透明なテクスチャを作成する Brush の一種です。
UWP アプリにアクリル素材を実装するには、[AcrylicBrush](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.acrylicbrush) のオブジェクトを自分で定義するか予め定義されているリソースを利用します。

以下に、リソース定義されたアクリル素材を実装する UWP アプリのコードとその実行画面を示します。

```xml:MainPage.xaml
<Grid Margin="20">
    <!-- Grid を上下左右に4分割 -->
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Rectangle Grid.Row="0" Grid.Column="0"
               Fill="{ThemeResource SystemControlAcrylicWindowBrush}"/>
    
    <Rectangle Grid.Row="0" Grid.Column="1"
               Fill="{ThemeResource SystemControlAccentAcrylicWindowAccentMediumHighBrush}"/>
    
    <Grid Grid.Row="1" Grid.Column="0">
        <Ellipse Fill="Red"/>
        <Rectangle Fill="{ThemeResource SystemControlAcrylicElementBrush}"/>
    </Grid>
    
    <Grid Grid.Row="1" Grid.Column="1">
        <Ellipse Fill="Red"/>
        <Rectangle Fill="{ThemeResource SystemControlAccentAcrylicElementAccentMediumHighBrush}"/>
    </Grid>
</Grid>
```

<img width="600" alt="ac0.png" src="https://qiita-image-store.s3.amazonaws.com/0/75597/5d132cea-521d-aa7f-16eb-5202d4bbffcc.png">


リソースキーに AcrylicWindow が含まれているリソースがウィンドウの背景を表示するアクリル素材（Background acrylic）で、AcrylicElement が含まれているリソースがアプリ内のアクリル素材（In-app acrylic）です。
また、Accent が含まれているリソースは、Windows の個人用設定でユーザ指定されたアクセントカラーが反映されるアクリル素材です。

ここで紹介した他にも、色合いの不透明度などが異なるアクリル素材がリソース定義されています。

より詳しいアクリル素材についての情報は [Acrylic material - UWP app developer | Microsoft Docs](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic) を参照してください。
このページでは、アクリル素材のリソース一覧や自分好みのアクリル素材を定義する方法、ウィンドウのタイトルバーにアクリル素材を実装する方法などを知ることができます。



# 接続型アニメーション（Connected animation）
接続型アニメーション（Connected animation）を使用すると、2つの異なるビュー間でのトランジション時に、それぞれのビューに共通する要素が接続しているように見えるトランジションを作成することができます。

今回は、遷移元のビューとして MainPage、遷移先のビューとして SubPage を作成し、接続型アニメーションで MainPage から SubPage へ遷移する UWP アプリの実装方法を紹介します。

## 基本的な実装
まず、XAML から実装していきます。
遷移元である MainPage に次の2つを配置します。

- 遷移を開始するための Button
- 遷移先の SubPage と共通する UIElement（ここでは Image）

```xml:MainPage.xaml
<Grid>
    <Button Content="Navigate" Click="Button_Click"/>
    <Image x:Name="SourceImage"
            Width="200"
            Height="200"
            Source="Lenna.png"/>
</Grid>
```

<img width="600" alt="ca1.png" src="https://qiita-image-store.s3.amazonaws.com/0/75597/ad78d9a3-881b-0325-b719-43d6e382f716.png">




次に、遷移先である SubPage を作成します。

<img width="600" alt="ca2.png" src="https://qiita-image-store.s3.amazonaws.com/0/75597/403f40b0-c171-66be-2f71-e0f12ab91888.png">


そして、遷移元の MainPage と共通する要素（Image）を配置します。
遷移したことがわかりやすいように、Image の配置を左上に設定し、Image の幅と高さを MainPage のときの2倍にしています。

```xml:SubPage.xaml
<Grid>
    <Image x:Name="DestinationImage"
            Width="400"
            Height="400"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Source="Lenna.png" />
</Grid>
```

<img width="600" alt="ca3.png" src="https://qiita-image-store.s3.amazonaws.com/0/75597/911f462b-bb8d-0af7-97ca-c8af1f4bab09.png">


以上で XAML の記述は終了です。  

<br>

続いて、コードビハインドにトランジションの処理を記述していきます。

まず、MainPage に配置した Button が押されたときに、接続型アニメーションで SubPage に遷移するコードを MainPage.xaml.cs に記述します。

```csharp:MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("key", SourceImage);
    Frame.Navigate(typeof(SubPage));
}
```

接続型アニメーションを使用するためには、システムに対してアニメーションに参加することを示す必要があります。
それを行うために、ConnectedAnimationService.GetForCurrentView() で現在の
 ConnectedAnimationService のインスタンスを取得し、PrepareToAnimate("key", SourceImage) で SourceImage がアニメーションに参加することを示します。ここで、メソッド PrepareToAnimate に渡す2つの引数は、トランジションに使用するユニークなキーとアニメーションを適用する UIElement への参照です。


一方、SubPage のコードビハインド SubPage.xaml.cs には、SubPage が読み込まれたときにアニメーションを開始するように以下を記述します。

```csharp:SubPage.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    var animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("key");
    animation?.TryStart(DestinationImage);
}
```

このコードでは、メソッド GetAnimation を呼び出してアニメーションのインスタンスを取得し、そのインスタンスが null でなければメソッド TryStart を呼び出してアニメーションを開始します。ここで、GetAnimation に渡す文字列には、遷移元で PrepareToAnimate に渡したキーと同じ文字列を指定します。


以上でコードビハインドの実装は終了です。
UWP アプリをビルドして実行すると、ページ間で画像が接続しているように見えるトランジションが作成できていると思います。

<img width="600" src="https://i.imgur.com/UpqPaEF.gif">



## Coordinated animation の実装
Coordinated animation では、接続型アニメーションのターゲットと協調して別の要素もアニメーションさせることができます。

本記事では、Coordinated animation の使用例として、画像と協調してテキストをアニメーションさせる方法を紹介します。

まず、SubPage.xaml を次のように修正します。

```xml:SubPage.xaml
<Grid>
    <!-- Grid を左右に分割 -->
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="400"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    
    <Image x:Name="DestinationImage"
            Width="400"
            Height="400"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Source="Lenna.png" />
    
    <!-- DestinationImage と協調してアニメーションする要素 -->
    <StackPanel x:Name="DescriptionRoot" Grid.Column="1" Margin="20 0 0 0">
        <TextBlock Text="Title" FontSize="50"/>
        <TextBlock TextWrapping="Wrap" FontSize="30">
            description description description description description description
            description description description description description description
        </TextBlock>
    </StackPanel>
</Grid>
```

<img width="600" src="https://i.imgur.com/6KWCivn.png">



DescriptionRoot という名前の StackPanel を配置しています。
StackPanel の内側には、画像の説明文のようなテキストを配置しています。

そして、その StackPanel を画像と協調してアニメーションさせるために SubPage.xaml.cs を次のように修正します。

```csharp:SubPage.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    // 省略
    animation?.TryStart(DestinationImage, new UIElement[] { DescriptionRoot });
}
```

メソッド TryStart の第2引数に new UIElement[] { DescriptionRoot } を指定しました。

以上の修正を行った UWP アプリの動作を次の図に示します。


<img width="600" src="https://i.imgur.com/gQmDHa1.gif">


画像が移動する途中でテキストも一緒に付いてくるアニメーションになりました。


## その他の実装
上記で紹介した他にも、ListView などのアイテムをクリックしたときにアニメーションが開始するような接続型アニメーションの実装も可能です。
詳しくは、[Connected animation - UWP app developer | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/uwp/design/motion/connected-animation) を参照してください。


# 視差（Parallax）
視差（Parallax）は、手前にある要素が後ろにある要素よりも速く移動する視覚効果です。
UWP では、この視差を作り出すコントロールとして [ParallaxView](https://docs.microsoft.com/ja-jp/uwp/api/Windows.UI.Xaml.Controls.Parallaxview) を使用することができます。

ParallaxView を使用して UWP アプリに視差を実装する例として、リストをスクロールすると、それに応じて背景画像も移動するコードを次に示します。

```xml:MainPage.xaml
<Grid>
    <ParallaxView Source="{x:Bind ForegroundElement}" VerticalShift="50">
        <Image Source="background.png" Stretch="UniformToFill"/>
    </ParallaxView>

    <ListView x:Name="ForegroundElement">
        <x:String>Item 1</x:String>
        <x:String>Item 2</x:String>
        <x:String>Item 3</x:String>
        <x:String>Item 4</x:String>
        <x:String>Item 5</x:String>
        <x:String>Item 6</x:String>
        <x:String>Item 7</x:String>
        <x:String>Item 8</x:String>
        <x:String>Item 9</x:String>
        <x:String>Item 10</x:String>
    </ListView>
</Grid>
```
ParallaxView では、手前の要素を ParallaxView の Source プロパティにバインドし、後ろの要素を ParallaxView の子として追加することで、2つの要素の間に視差効果を作ります。
ただし、手前の要素は、ListView などのように ScrollViewer を含む要素である必要があります。

ParallaxView の VerticalShift プロパティは背景が垂直にどのくらい移動するかを指定するもので、0を指定すると背景が移動しないことを意味します。
一方、背景を水平方向に動かしたい場合は、HorizontalShift プロパティを指定します。

次に示す図は作成した UWP アプリの動作です（リストのアイテム数を増やしています）。

<img width="600" src="https://i.imgur.com/J1EJ2Zj.gif">


視差についてのより詳しい情報は、[How to use the ParallaxView control to add depth and movement to your app. - UWP app developer | Microsoft Docs](https://docs.microsoft.com/en-us/windows/uwp/design/motion/parallax) を参照してください。


# 表示（Reveal highlight）
表示（Reveal highlight）は、マウスポインタがコントロールに近づいたときに、そのコントロールの周囲に隠れた境界線を表示する照明効果です。
この「表示」効果は以下のコントロールにおいて、デフォルトで有効になっています。

- ListView
- GridView
- TreeView
- NavigationView
- AutosuggestBox
- MediaTransportControl
- CommandBar
- ComboBox

上記以外のコントロールに対して「表示」効果を実装するには、Style プロパティを設定します。
例えば、Button コントロールに「表示」効果を実装するには、次のコードのように ButtonRevealStyle を指定します。

```xml
<Button Content="Button" Style="{ThemeResource ButtonRevealStyle}"/>
```

<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/75597/13b55c92-5f13-d0d3-bb70-af02d555d3f5.jpeg"/>


「表示」効果を実装したボタンには、マウスポインタの周囲だけ光があたっているような境界線が表示されています。

また、別の例として、GridView のアイテムに対して「表示」効果を実装するには ItemContainerStyle プロパティを次のように設定します。

```xml
<GridView ItemContainerStyle="{ThemeResource GridViewItemRevealBackgroundShowsAboveContentStyle}">
    <GridViewItem>
        <Rectangle Width="300" Height="300" Fill="#333"/>
    </GridViewItem>
</GridView>
```

<img width="600" src="https://i.imgur.com/RAtgrYr.jpg"/>



「表示」の詳細は、[Reveal highlight - UWP app developer | Microsoft Docs](https://docs.microsoft.com/en-us/windows/uwp/design/style/reveal) を参照してください。


# まとめ
本記事では、UWP アプリで使用することができる Fluent Design System の4つの機能について紹介し、それらの機能を UWP アプリに実装するための簡単なサンプルコードを示しました。

ほとんどコードを書く必要なく素敵な画面効果を実装できるのは素晴らしいですね！


# 参考にしたページ
Fluent Design System について

- [Fluent Design System for UWP apps - UWP app developer | Microsoft Docs]( https://docs.microsoft.com/en-us/windows/uwp/design/fluent-design-system/)
- [Windows 10 Fall Creators Updateで導入された「Fluent Design System」の4つの機能とは？：特集：マイクロソフトテクノロジーの現在と未来 - ＠IT](http://www.atmarkit.co.jp/ait/articles/1711/17/news015.html)

Fluent Design な UWP アプリとそのサンプルコード

- [Microsoft/BuildCast - GitHub](https://github.com/Microsoft/BuildCast)
- [Microsoft/WindowsUIDevLabs - GitHub](https://github.com/Microsoft/WindowsUIDevLabs)
- [Windows-universal-samples/Samples/XamlUIBasics - GitHub](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlUIBasics)
- [XAML Controls Gallery - Microsoft ストア](https://www.microsoft.com/ja-jp/store/p/xaml-controls-gallery/9msvh128x2zt)

Acrylic material について

- [Acrylic material - UWP app developer | Microsoft Docs](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic)
- [自分好みのAcrylicBrushを作成してみる – My Reference Blog](http://www.myrefblog.com/archives/9774) 

Connected animation について

- [Connected animation - UWP app developer | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/uwp/design/motion/connected-animation) 

Parallax について

- [How to use the ParallaxView control to add depth and movement to your app. - UWP app developer | Microsoft Docs](https://docs.microsoft.com/en-us/windows/uwp/design/motion/parallax)

Reveal highlight について

- [Reveal highlight - UWP app developer | Microsoft Docs](https://docs.microsoft.com/en-us/windows/uwp/design/style/reveal)