PowerAppsでハンバーガーメニュー作ってみた

# PowerAppsでハンバーガーメニューしたい！

ただそれだけです。
ただ今回イメージしているのはどっちかと言うと、Material Designで言う所のナビゲーションドロワーです。
こんな感じのです。最近よく見かけますよね。

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="css,result" data-user="kolpak" data-slug-hash="WxrGmp" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Hamburger menu  #2">
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
  

WEBデザインの世界ではハンバーガーメニューは賛否両論あるみたいですが、これできたらPowerAppsのモバイルレイアウトとかもっとオシャレにつくれるんじゃね？と思ったのでまぁとりあえずやってみたいと思います。

##### 今回の内容はわりとロジック寄りの話になります。

## まずは簡単な表示・非表示で実装
WEBでよく見かけるのは画面外からニュルッと出てくる事が多いですが、PowerAppsでそれをやろうとするとちょっと面倒そうです。とりあえずはVisible切り替えてそれっぽいの作ってみましょう。

#### できた。
![ToggleVisibleDemo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243135/9626703d-a1f1-a68f-d19e-c007d8235cd4.gif)

動きは単純ですね。
部品はこうなってます。
![ToggleVisibleTreeView.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243135/402ab628-4544-2edc-4d4f-1963e9a909ac.jpeg)

メニュー本体のGalleryと✕アイコン、後は背景暗くする四角形の `Visible` は `MenuVisible` というコンテキスト変数にしています。
ハンバーガーメニューのアイコンの `OnSelect` で、

``` Text:OnSelect
UpdateContext({MenuVisible: true})
```

みたいな感じで表示させて、
バツアイコンと、暗い背景の `OnSelect` では、

``` Text:OnSelect
UpdateContext({MenuVisible: false})
```

のようにして、Visibleを切り替えているだけです。簡単！
バツアイコンがあるので、別に暗い背景の方で非表示にしなくてもいいんですが、普段使っているとこういうメニューってメニュー外をクリックしたら消えるイメージありません？


## 次はニュルッとさせたい！
さて、どうしましょう。PowerAppsにはコントロールを移動させるというプロパティはありません。
しょうが無いので、Timerコントロールで `X` を変えるしかないでしょうか。

`Transition` プロパティみたいなのを作って欲しい！

#### で、つくってみた。
![DrawerVisibleDemo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243135/c145f366-a070-891b-8eb3-c430514200d3.gif)
正直あまりきれいなニュルッとではありませんが、こうなりました。
  

そしてこれを実現する部品たちです。
![DrawerVisibleTreeView.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243135/f3af1658-6e35-9ef2-ffd0-92ffbcec06c2.jpeg)

部品としてはタイマーコントロールを2つ追加しただけですが、関数の中で何やらゴチャゴチャしています。
ここから先はTimerコントロールの動きがわかっている前提で進めます。

わからん！という方は以下を読んで理解してください。
[タイマー コントロール: リファレンス - PowerApps | Microsoft Docs](https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/controls/control-timer)



まずはスクリーンの `OnVisible` でいろいろ初期化します。

``` Text:OnVisible
UpdateContext(
    {
        MenuX: -DrawerMenuGallery.Width,    // ギャラリーの初期位置（X座標）。幅の分だけ画面の左外に出ててもらう。
        SlideRightStart: false,             // 右スライドの開始フラグをOFFに
        SlideLeftStart: false,              // 左スライドの開始フラグをOFFに
        SlideRightRepeat: true,             // 右スライドタイマーのループをONに
        SlideLeftRepeat: true,              // 左スライドタイマーのループもONに
        MenuVisible: false,                 // 薄黒背景のVisibleは初期OFF
        MenuCloseVisible: false             // バツボタンのVisibleは別出しにしました。初期OFF（理由は後述）
    }
)
```

特に大事なのが、最初の一個目です。
画面の左からスライドして出てきてほしいので、実体は画面外にいて欲しいです。
ピッタリ画面の左端外にいてほしいので、マイナス自分の幅を指定しています。
CSSとかで実装するときもよく同じ様な考え方をするかと思います。

絵で見るとこんな感じです。
![GalleryWidth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243135/3d945a28-63e2-8f09-7688-5f1e20f89405.jpeg)
ちなみに、画像のように画面外でも `Visible` が `true` になっていれば描画されますが、見えてるコントロールは触れなくなるみたいなので、プロパティをいじる時とかはツリービューから選択しましょう。


次に、ハンバーガーメニューの `OnSelect` です。

``` Text:OnSelect
Concurrent(
    UpdateContext({MenuVisible: !MenuVisible}),    // 薄黒背景のVisibleをONに
    UpdateContext({SlideRightStart: true})         // 右スライドを開始！
)
``` 

`Concurrent()` は中に書いた関数たちを非同期に実行してくれます。別にこうしなくても見た目良いですが、画面暗くなりながらメニューが出てくる、という動作にしたかったのでこうしてみました。正直変わらんｗ

そして、右スライドタイマーの `OnTimerEnd` は、

``` Text:OnTimerEnd
If( 
    MenuX < 0,                              // ギャラリーのX座標 (MenuX) が、0 以下のとき（＝画面外の部分がまだある時）
    UpdateContext({MenuX: MenuX + 100}),    // [TRUE] 右へ +100 ずらす。（＝100ピクセル？だけ画面内に入ってくる）
    UpdateContext(                          // [FALSE]（つまり、メニューが画面内に入りきった時）
        {
            SlideRightRepeat: false,        // 右スライドのループをOFFに。（右スライドタイマーが停止する）
            SlideRightStart: false,         // 右スライドの開始フラグをOFFに。
            SlideLeftRepeat: true,          // 左スライドのループをONに。（左に戻すための初期化）
            MenuCloseVisible: true          // バツボタン表示
        }
    )
)
```

ここまでで、ギャラリーをニュルッと表示させることができます。
ちなみにTimerの `Duration` は `1` です。

文字だけで見るとややこしいですねー。全然ローコードとは思えない（泣）


続いてバツボタンを押したときに、メニューが画面外へお帰りいただくよう実装していきます。

まずはバツボタンや薄黒背景触ったときの `OnSelect` から。

``` Text:OnSelect
UpdateContext(
    {
        SlideLeftStart: true,     // 左スライド開始！
        SlideRightRepeat: true    // 右スライドのループをtrueに戻しておく。（右スライド終わった時点で一回falseにしてるので）
    }
);

```

そして、左スライドタイマーの `OnTimerEnd` です。

``` Text:OnTimerEnd
If(
    MenuX > -DrawerMenuGallery.Width,       // ギャラリーのX座標がマイナス自分の幅より大きい時（画面内にまだ残っている間）
    UpdateContext({MenuX: MenuX - 100}),    // [TRUE] 自分を100ずつ左にずらす。
    UpdateContext(                          // [FALSE] つまり、自分が画面内から消え去ったとき。
        {
            SlideLeftRepeat: false,         // 左スライドのループを止める。
            SlideLeftStart: false,          // 左スライドの開始フラグをOFFに。
            SlideRightRepeat: true,         // 右スライドのループをONに。（右スライドを動かすための初期化）
            MenuVisible: false,             // 薄黒背景除去。
            MenuCloseVisible: false         // バツボタン除去。
        }
    )
);
```

これで一通り終了（のはず）です。

もしかしたらもっと上手いやり方があるかもしれません。
ここまでして作る意味があるかと言われると微妙ですが、まぁそれっぽいものができたので満足です。


## おまけ
こーゆーのもよく見ますよね。
![Omake.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243135/be9b8010-8696-c4fc-04c2-34769821d6f8.gif)