PowerAppsでアニメーション付きで操作が楽しいアコーディオンメニュー

・前回は、アニメーションなしのアコーディオンメニューを作ったのですが、アニメーションなしでパッパッと切り替わるだけでした。
アコーディオンといえば、蛇腹部分を広げたり閉じたりして演奏する楽器ですので、ちゃんとアニメーションさせてみます。
## 動画も公開しています
<iframe width="560" height="315" src="https://www.youtube.com/embed/kQEhpXVpO88?si=ofiT2MHD9qoE5Rre" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
↑動画を公開しました！



![アコーディオンメニューアニメ-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3880604/f3528590-7c50-74de-1cca-a45fe463dcbe.gif)
こんな感じでそれぞれアニメーションしながらメニューが閉じたり広がったりすると、まさにアコーディオンといった趣きになりますね。
## メニューの配置
前回に引き続き
![アコーディオンメニュー配置.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3880604/5276bbab-6fb3-cfb0-e811-722bd34d1d8c.png)
垂直コンテナ(赤)の中に、ボタンと垂直コンテナ(黄)を交互に配置します。垂直コンテナ(黄)の中には、小項目メニューのボタンをそれぞれ４つ配置しています。

```
垂直コンテナ(赤)
      ┝大項目ボタン1
      ┝垂直コンテナ(黄)1
            ┝小項目ボタン
            ┝小項目ボタン
            ┝小項目ボタン
            └小項目ボタン
      ┝大項目ボタン2
      ┝垂直コンテナ(黄)2
            ┝小項目ボタン・・・４つ
      ┝大項目ボタン3
      ┝垂直コンテナ(黄)3
            ┝小項目ボタン・・・４つ
      ┝大項目ボタン4
      ┝垂直コンテナ(黄)4
            ┝小項目ボタン・・・４つ
```
配置イメージは上記の通りで
左上のメニューアイコンで、垂直コンテナ(赤)の開閉アニメーションさせます。
大項目ボタン〇で垂直コンテナ(黄)〇を開閉アニメーションさせる。
という設定をしていきます。

## 画面のOnVisibleプロパティの設定
画面を読み込んだ際に、変数をリセットしたいので
画面のOnVisibleプロパティに以下を設定します。
```javascript
Reset(Timer1);Reset(Timer2);//タイマーのリセット
//垂直コンテナ(赤)の表示制御用
Set(_menuTitle,false);
//垂直コンテナ(赤)開いているかどうか判定用
Set(_menuTitleopen,false);
//垂直コンテナ（黄）の表示制御用
Set(_menu1,false);
Set(_menu2,false);
Set(_menu3,false);
Set(_menu4,false);
//垂直コンテナ（黄）が開いているかどうか判定用
Set(_menu1open,false);
Set(_menu2open,false);
Set(_menu3open,false);
Set(_menu4open,false);
```

## タイマーの設置
タイマーを垂直コンテナ（赤）と垂直コンテナ（黄）用に2つ設置します。
Timer1とTimer2のプロパティは以下

Timer1は
Duration：300
Start：_timer1start
OnTimerEndに以下
```javascript
//true(開いたとき)なら開き判定用の変数をtrueにする、falseなら(閉じるとき)はfalseにする
If(_menuTitle,Set(_menuTitleopen,true),Set(_menuTitleopen,false));
//垂直コンテナ（黄）の表示制御用と開き判定用の変数をfalseにして垂直コンテナ（黄）を全て閉じる
Set(_menu1open,false);
Set(_menu2open,false);
Set(_menu3open,false);
Set(_menu4open,false);
Set(_menu1,false);
Set(_menu2,false);
Set(_menu3,false);
Set(_menu4,false);
//垂直コンテナ（黄）アニメーション用のタイマーをリセット
Reset(Timer2);
```
垂直コンテナ(赤)が開かれているかどうかを_menuTitleopenに設定し、変数をfalseにして、Timer2をリセットします。

Timer２は
Duration：300
Start：_timer2start
OnTimerEndに以下
```javascript
//それぞれtrue(開いたとき)なら開き判定用の変数をtrueにする、
//false(閉じるとき)ならfalseにする
If(_menu1,Set(_menu1open,true),Set(_menu1open,false));
If(_menu2,Set(_menu2open,true),Set(_menu2open,false));
If(_menu3,Set(_menu3open,true),Set(_menu3open,false));
If(_menu4,Set(_menu4open,true),Set(_menu4open,false));
```
こちらは、垂直コンテナ（黄）がそれぞれ開かれているかどうかを判定するために必要な変数「_menu〇open」の設定です。開いたときにtrue、閉じたときにfalseすることで、どの垂直コンテナ（黄）が開いているのか判定できるようにします。

## メニューアイコンのプロパティ設定
左上のメニューアイコンのOnSelectプロパティに以下
```javascript
//タイマーのリセット(０に戻す)
Reset(Timer1);
//変数をfalseからtrueにしてTimer1をスタートする
Set(_timer1start,false);
Set(_timer1start,true);
//垂直コンテナ(赤)表示用の変数を反転(trueならfalseにし、falseならtrueにする)する
Set(_menuTitle,!_menuTitle);
```
メニューアイコンを押した際にTimer1をスタートさせて、垂直コンテナ(赤)をアニメーションさせます。

## 垂直コンテナ(赤)のプロパティ設定
垂直コンテナ(赤)のHeightプロパティに以下
```javascript
With(
    {//垂直コンテナ(赤)内のボタンと垂直コンテナ（黄）の高さを全て足した値を変数_menuheightに入れる
        _menuheight: Button_1.Height + Button_2.Height + Button_3.Height + Button_4.Height
        + menu_1.Height + menu_2.Height + menu_3.Height + menu_4.Height},
    If(
        _menuTitle,//trueなら垂直コンテナ(赤)を開くアニメーション
        _menuheight / Timer1.Duration * Timer1.Value,
        If(
            _menuTitleopen,//垂直コンテナ(赤)が開いていたら、閉じるアニメーション
            _menuheight - _menuheight / Timer1.Duration*Timer1.Value,
            0
        )
    )
)
```
Heightプロパティは非動作プロパティなので、Set関数やUpdateContext関数による変数の設定ができません。
そこで、数式内のみで変数を使用できるWith関数を活用しています。

With関数で、全ての大項目ボタンの高さ「ButtonTitle_〇.Height」と垂直コンテナ（黄）の高さ「menu_〇.Height」を合計した数値を_menuheigtに入れています。({}内の部分)
If内の数式で_menuheigtを元にタイマーの値から高さを計算しています。
Timer1.Valueの値に応じて閉じたり開いたりアニメーションします。

## 大項目ボタンの設定
次に小項目である垂直コンテナ(黄)を表示させるために
大項目のボタンのOnSelectプロパティに以下を設定します。

```javascript
//Timer2をリセット(0に戻す)
Reset(Timer2);
//変数をfalseからtrueにし、Timer2をスタートする
Set(_timer2start,false);
Set(_timer2start,true);
//開きたい垂直コンテナ（黄）を開き、それ以外を閉じる
Set(_menu1,!_menu1);
Set(_menu2,false);
Set(_menu3,false);
Set(_menu4,false);。
```
Timer2をリセットして、スタートさせます。
大項目のボタンの1つ目用です。
2つ目以降に貼り付けた後、それぞれ_menu1を変更してください。
表示する垂直コンテナ（黄）以外の変数をfalseにします。

## 垂直コンテナ(黄)のプロパティ設定
垂直コンテナ(黄)のHeightプロパティに以下を設定します。

```javascript
If(
    _menu1,//trueなら開くアニメーション
    200 / Timer2.Duration * Timer2.Value,
    If(
        _menu1open,//開いていたら閉じるアニメーション
        200 - 200 / Timer2.Duration*Timer2.Value,
        0
    )
)
```
_menu1と_menu1openを、設定する垂直コンテナ(黄)の変数に合わせて変更してください。
こちらもTimer2.Valueの値に応じて高さが変わるため、アニメーションして開閉します。
内容は垂直コンテナ(赤)と変わらないのですが、高さを決め打ちで200にしているのでシンプルになっています。
小項目の数に応じて、値を変更してください。
※５にするなら250とか３つにするなら150とか

垂直コンテナ(黄)の高さについてですが、FillPortionsプロパティは０(「高さ(伸縮可能)」をオフ)にしてください。1(オン)にすると開いたままになってしまいました。

ちなみに垂直コンテナ(赤)の高さも決め打ちしようとしたのですが、開いたときのメニューの高さが変動してアニメーションが不自然になるので、ちゃんと全て足して計算させています。

## 最後に
説明通りにコントロールを配置して、プロパティを設定すれば
アニメーション付きのアコーディオンメニューが完成したと思います。
もし誤りがありましたら、お知らせください。

こういう動きのあるメニューは、ユーザーの目を惹くし、操作するだけでも楽しいです。
ぜひ試して見てください。