#PowerApps でカルーセルスライダーを作ってみよう

#概要
Power Appsはビジネスアプリケーションを作成するプラットフォームですが、それだけでなく、個人利用のアプリの作成にも適しています。
今回はPower Appsの標準コントロールでは提供されていない、カルーセルスライダーを作成する方法を紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/37bbcf10-ae62-d451-85da-2359860ac33b.png)

特に、題材として、[Alan](https://twitter.com/alanchai)の作成した[ビデオポータルアプリ](https://twitter.com/alanchai/status/1200315856888238082?s=20)を使います。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I thought I had post this before, but apparently not. An &quot;old&quot; app from Feb 19, persona based video on-demand portal. Change in app making approach - Put UX first, not functionality and you can stretch Power Apps to beyond normality. Enjoy!😉<a href="https://twitter.com/hashtag/PowerApps?src=hash&amp;ref_src=twsrc%5Etfw">#PowerApps</a><a href="https://twitter.com/hashtag/PowerAddicts?src=hash&amp;ref_src=twsrc%5Etfw">#PowerAddicts</a><a href="https://twitter.com/MSPowerApps?ref_src=twsrc%5Etfw">@MSPowerApps</a> <a href="https://t.co/keoBFdpUvU">pic.twitter.com/keoBFdpUvU</a></p>&mdash; Alan Chai @Houston #PowerApps #PowerAddict (@alanchai) <a href="https://twitter.com/alanchai/status/1200315856888238082?ref_src=twsrc%5Etfw">November 29, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

一番上のビデオが横にスクロールできるようになっていますが、これをカルーセルスライダーにします。

完成したパーツでは以下のように表示されます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Power Appsでカルーセルスライダーを作ってみました。 <a href="https://t.co/XQfRz0bCL2">pic.twitter.com/XQfRz0bCL2</a></p>&mdash; Hiro (@mofumofu_dance) <a href="https://twitter.com/mofumofu_dance/status/1201018213733060608?ref_src=twsrc%5Etfw">December 1, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

(Advent Calendarの2日目がこれでいいのか？！)


#カルーセル用データ
カルーセルスライダーはGalleryコントロールで作りますが、このアイテムのコレクションは以下のような構成にしています。※ここでは10個のビデオリストがあると仮定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/fdbf40db-c383-45a2-9069-332bfca2c570.png)
"Order:1"には、ソースデータの最終行を追加します。また、最後の2つのデータは、ソースデータの1,2行目を追加します。

元のデータソース名をVideoListと仮定すると、データ作成用の数式は以下のように書けます(App.OnStartなどに設定)

```
Clear(colVideos);
/*Add data from last row with order=1*/
Collect(
    colVideos,
    Last(
        AddColumns(
            VideoList,
            "Order",
            1
        )
    )
);
/*Copy data from source list*/
ForAll(
    VideoList,
    Collect(
        colVideos,
        Last(
            FirstN(
                AddColumns(
                    VideoList,
                    "Order",
                    id+1
                ),
                CountRows(colVideos)
            )
        )
    )
);
/*Add First 2 data of source list to Collection*/
ForAll(
    [1,2],
    Collect(
        colVideos,
        Last(
            FirstN(
                AddColumns(
                    VideoList,
                    "Order",
                    CountRows(colVideos)+1
                ),
                Value
            )
        )
    )
);
```

ギャラリーに表示してみると、期待通りデータが生成されているのがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/5884f363-8156-f98d-509c-96d3aa0766f0.png)

#パーツ構成
画面上のパーツ構成はシンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/c67b14e1-4ca7-8b0b-668e-77c49f293d0f.png)

- Gallery : カルーセルの本体。レイアウトはHorizontalにする。Xを画面外に設定し、Widthは画面の幅+Videoコントロールの幅x2
    - Button : ギャラリー内のビデオコントロールを触れないようにするためのマスク。OnSelectでスライダーを止める効果もある
    - Video : CollectionのVideoURLを指定する
- Timer : カルーセルスライダーを動かすためのタイマー。AutoStart:true, Repeat:true
- Video2 : スライダー内で選択されたビデオを表示するために配置する。
- Icon : Video2を非表示にして、スライダーの動きを再開するために配置。

以降では各コントロールに設定するプロパティを解説します。

##Timer control
タイマーはカルーセルスライダーの重要な要素です。
よくWebサイトで見かけるような、[移動]-->[静止]-->[移動]-->[静止]-->の動きを再現するために、ここでは2つの時間に関する変数(T , Ttot)を定義します。それぞれの変数は関連づいていて、Ttotは画面を表示している間、ビデオを選択していない時間を記録する変数です。一方のTは、Ttotが2000ミリ秒経過するうちの1000ミリ秒だけ変化する変数とします。つまり図で表すと以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/4bcedf26-246e-ad4b-fa89-fb268aa79316.png)

これだけだと、ユーザーがカルーセルの中のアイテムを選択している間もスライダーが動いてしまうので、ユーザーがアイテムを選択したときには変数の更新を止めるようにします。これを実現するために、アイテムの選択状態として```showVideo```というTrue/Falseの変数を用意します。

最終的に、タイマーのOnTimerEndは以下のように書かれます。

```Timer1.OnTimerEnd
If(
    /*Condition1: Video is not selected AND Ttot is (even number)*1000 */
    And(
        !showVideo, 
        Mod(
            RoundDown(
                Ttot / 1000,
                0
            ),
            2
        ) = 0 
    ),
    UpdateContext({T: T + Timer1.Duration});
    UpdateContext({Ttot: Ttot + Timer1.Duration}),
    /*Condition2: Video is not selected AND Ttot is not (even number)*1000 */
    !showVideo,
    UpdateContext({Ttot: Ttot + Timer1.Duration})//T is not updated
);
/*Cyclic: When video moves XX times, then Reset T*/
If(
    T = 1000*(CountRows(colVideos)-3),
    UpdateContext({T: 0})
)
```

以上でほとんど完了です。あとはGalleryコントロールを見ていきます。


##Gallery Control
今回はメインのアイテムの左右に、隣接する順番のビデオを半分だけ表示したいので、コントロールの一部を画面外に表示させる必要があります。
また、右から左にアイテムが流れていきますが、最後のビデオを表示させるために、画面の右方向にもコントロールをはみ出させる必要があります。
※スクリーンの外側にコントロールを配置する場合のTIPSは[こちら](https://qiita.com/h-nagao/items/6870610d23a18305b9d9)をご覧ください。

これらを踏まえると、GalleryのX,Widthプロパティには以下の数式を設定すればいいことがわかります。

```Gallery.X
0-Gallery1.TemplateWidth*0.5
```

```Gallery.Width
Screen1.Width+Gallery1.TemplateWidth*CountRows(volVideos)/2
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/b2451ab9-d60c-a543-49a5-a1562845e977.png)

##Gallery内のVideo Control
ギャラリー内のビデオコントロールは、時間の変数Tに応じて、左に移動するように設定します。

```Video1.X
20-Gallery1.TemplateWidth*T/1000
````
20は余白です。Tが1000ミリ秒進むと、Gallery1のTemplateWidthの大きさだけ左にスライドします。(つまり次のアイテムが真ん中に表示される)
あとはデータソースのURLをメディアに指定してください。

##Gallery内のButton Control
ボタンコントロールはビデオに覆いかぶさるように設置します。また、ボタンクリックでタイマーを止め、選択したビデオを表示させたいので、各プロパティを以下のように設定します。


```Button1.Properties
Button1.X : Video1.X
Button1.Y : Video1.Y
Button1.Height : Video1.Height
Button1.Width : Video1.Width

Button1.OnTimerEnd : 
Select(Parent);
UpdateContext({showVideo:true});
```
以上でGallery内の設定は完了です。


#最後に
選択したビデオを表示する追加のVideoコントロールですが、これには```Gallery1.Selected.VideoURL```を指定し、Visibleに、showVideoを設定すればよいので、説明は省略します。

このようにして、標準で提供されていない、ちょっと使えるコントロールが作れました。
Power Appsでは少しの数式（ここでの数式もデータ生成部分以外はそれほど難しくはないはず）で多彩なカスタムコントロールを作成できます。
皆さんもぜひ自分のアプリに、「よく見るコントロール」を作成してみてください！

サンプルは以下から入手してください。
https://pamofumofu.blob.core.windows.net/files/CarouselSlider.msapp