Alexa APL, 第11回　タッチ対応　その5（画面更新（SetValueとFrame））

#はじめに
Alexaを搭載した画面付きデバイスの画面レイアウトを作成します。
画像、および商品名をリストアップした画面（商品リスト）を作成し、商品をタッチすると、その商品の詳細（詳細画面）に切り替わり、もう一度タッチするとリストに戻るレイアウトを作成します。
TouchWrapperコンポーネントを使って、タッチを検出し、SetValueで値を変更します。
「詳細画面」はFrameを使って表示します。
第10回では、画面半分を詳細表示に使って表示していましたが、今回は画面（Container）を「商品リスト」と「詳細画面」の二つを用意して、「詳細画面」の表示、非表示を切り替えることで今回のレイアウトを実現します。
今回の記事は第10回の焼き直しですみません。

#今回実施する内容
画像、および商品名をリストアップした画面（商品リスト）を作成し、商品をタッチすると、その商品の詳細（詳細画面）に切り替わり、もう一度タッチするとリストに戻るレイアウトを作成します。
TouchWrapperコンポーネントを使って、タッチを検出し、SetValueで値を変更します。
「詳細画面」はFrameを使って表示します。
中型デバイス（Echo Show用）
**商品リスト**
![中型デバイス1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/2173c95e-3cc0-ca4d-3feb-1ab65cb83774.jpeg)
**詳細画面**
![中型デバイス2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/87aa508c-9d90-4532-1a30-d2fb926827b9.jpeg)

#環境
OS:Windows 10 JP
Alexaスキル言語：Node.js
Editor：Visual Studio Code
APLバージョン：1.0, 1.1

#参考
・[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)
第1回のAlexa APLの記事です。タイトル通り、ハローAPLを表示させるだけのAPLです。

・[Alexa APL, 第6回　シーケンス(Sequence)を使ったレイアウト](https://qiita.com/Mount/items/be954f837ef96be8f022)
第6回のAlexa APLの記事です。Sequenceを使って画面レイアウトを作成するAPLの紹介です。

・[Alexa APL, 第10回　タッチ対応　その4（画面更新（SetValue））](https://qiita.com/Mount/items/23bee36fbfa026e6a060)
第10回のAlexa APLの記事です。SetValueを使って画面レイアウトを作成するAPLの紹介です。

・[APLコマンド](https://developer.amazon.com/ja/docs/alexa-presentation-language/apl-commands.html)
AmazonのAPLドキュメントにあるAPLコマンドの説明です。

・[標準コマンド](https://developer.amazon.com/ja/docs/alexa-presentation-language/apl-standard-commands.html)
AmazonのAPLドキュメントにあるコマンドの説明です。SendEventやSpeakItemの説明があります。

#用語
##APL
Alexa Presentation Language
amazonの画面つきのAlexaの画面表示用の言語。
JSONを使用した記載方法です。
インターネットのホームページはHTMLとCSSで作成しますが、AlexaはAPLで作成するということです。

##APLオーサリングツール
APL作成を視覚的に見ながらAPLのJSONファイルを作成するツール。
サンプルテンプレートも準備されており、その中から選択していくだけで、だいたいの画面は作成できる。

#前提条件
前提条件はとくにないといえばないですが、本まとめを読むにあたり、以下がわかっていることが前提です。
・alexa developer consoleのアカウントがある
・Alexaスキルを開発したことがある
・JSONの記載方法を知っている
・「Alexa ハローAPL、Alexaスキルの画面への対応」、「Alexa APL, 第6回　シーケンス(Sequence)を使ったレイアウト」、および「第10回　タッチ対応　その5（画面更新（SetValue））」の記事をみている

#画面を作成してみる
商品のリストアップとその詳細を示すが面のレイアウトを作成します。

##SetValueを使ったレイアウトの作成
これから作成する「レイアウト画面」はこんな感じです。
![レイアウト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/081359c7-5f5d-2a4b-115d-c5e26bbd835b.jpeg)

Containerの配下にSequenceとFrameがありますが、Sequence部分は、第10回で作成したものと同じです。
Frame部分が今回の変更箇所です。
Frame部分は**強調**で示します。

1. APLオーサリングツールを起動して「最初から作成」を選択する。 
2. 「レイアウト画面」の「mainTemplate」を選択し、「Container」を追加する。
3. 「レイアウト画面」で、「Container」を選択し、「Sequence」を追加する。
4. 「レイアウト画面」の「Sequence」を選択し、「詳細設定画面」で、以下をそれぞれ設定する。
・ data：${payload.sample.sampleArray}
・ height：**100vh**

5. 「レイアウト画面」で、「Sequence」を選択し、「Container」を追加する。
6. 「レイアウト画面」の「Container」を選択し、「TouchWrapper」を追加する。
7. 「レイアウト画面」の「Container」を選択し、「詳細設定画面」で、以下を設定する。
・ direction：row
8. 「レイアウト画面」で、「Container」を選択し、「Image」を追加する。
9. 「レイアウト画面」の「Image」を選択し、以下をそれぞれ設定する。
・ source：${data.imageURL}
・ width：20vw
・ height：20vh
10. 「レイアウト画面」で、「Container」を選択し、「Text」を追加する。
11. 「レイアウト画面」の「Text」を選択し、「詳細設定画面」で、以下を設定する。
・ text：${data.text}

**12. 「レイアウト画面」の一番上の「Container」を選択し、「TouchWrapper」を追加する。**
**13. 「レイアウト画面」の二番目の「TouchWrapper」を選択し、「詳細設定画面」で、以下を設定する。**
**・ display：invisible**
**・ id：msgBoxId**
**・ width：100vw**
**・ height：100vh**
**・ position：absolute**
**`display`を`invisible`に設定し、初期状態は非表示にします。**
**`position`は`absolute`に設定し、商品リストとは切り離し絶対位置で設定します。**
**14. 「レイアウト画面」の二番目の「TouchWrapper」を選択し、「Frame」を追加する。**
**15. 「レイアウト画面」の「Frame」を選択し、「詳細設定画面」で、以下を設定する。**
**・ backgroundColor：rgba(grey, 1.0)**
**・ width：100vw**
**・ height：100vh**
**16. 「レイアウト画面」の「Frame」を選択し、「Container」を追加する。**
**17. 「レイアウト画面」の上で作成した「Container」を選択し、「詳細設定画面」で、以下を設定する。**
**・ alignItems：center**
**・ direction：row**
**・ justifyContent：center**
**・ width：100vw**
**・ height：100vh**
**18. 「レイアウト画面」の上で作成した「Container」を選択し、「Image」を追加する。**
**19. 「レイアウト画面」の上で作成した「Image」を選択し、「詳細設定画面で、以下を設定する。**
**・ id：imageId**
**・ width：50vw**
**・ height：50vh**
**20. 「レイアウト画面」の上で作成した「Container」を選択し、「Text」を追加する。**
**21. 「レイアウト画面」の「Text」を選択し、「詳細設定画面」で、以下を設定する。**
**・ id：textId**
**・ width：50vw**
22. APL JSONの画面を開いて、一番目の「TouchWrapper」の記載を以下の通り、`onPress`の`type`に`SetValue`を設定し、以下の通りにする。**第10回とmsgBoxIdにSetValueを実施するところが違います。**

```json:一番目TouchWrapperのAPL
...
"type": "TouchWrapper",
"onPress": [
    {
        "type": "SetValue",
        "componentId": "msgBoxId",
        "property": "display",
        "value": "normal" 
    },
    {
        "type": "SetValue",
        "componentId": "imageId",
        "property": "source",
        "value": "${data.imageURL}" 
    },
    {
        "type": "SetValue",
        "componentId": "textId",
        "property": "text",
        "value": "${data.detail}"
    }
],
...
```

**23. APL JSONの画面を開いて、二番目の「TouchWrapper」の記載を以下の通り、`onPress`の`type`に`SetValue`を設定し、以下の通りにする。**

```json:二番目TouchWrapperのAPL
...
"type": "TouchWrapper",
"onPress": [
    {
        "type": "SetValue",
        "componentId": "msgBoxId",
        "property": "display",
        "value": "invisible" 
    },
...
```

##JSONデータの作成
以下の通り、JSONデータを作成する。

```json:JSONデータ
{
    "sample": {
        "sampleArray": [
            {
                "text": "コーヒー",
                "detail": "コーヒーです。",
                "imageURL": "https://coffee_480x480.jpg"
            },
            {
                "text": "カプチーノ",
                "detail": "カプチーノです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？",
                "imageURL": "https://cappuccino_480x480.jpg"
            },
            {
                "text": "カフェラテ",
                "detail": "カフェラテです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？<br>カプチーノとはミルクの量が違う？",
                "imageURL": "https://latte_480x480.jpg"
            },
            {
                "text": "エスプレッソ",
                "detail": "エスプレッソです。<br>加圧して抽出したもので、コーヒーよりもかなり濃いです。",
                "imageURL": "https://espresso_480x480.jpg"
            }
        ]
    }
}
```

##SetValueの説明、Frameの説明
`TouchWrapper`の`onPress`に`SetValue`を設定することで今回の機能を実現します。
第10回でSetValueの説明はしましたので、ここでは説明していない部分をかいつまんで説明します。

・ 一番目の`TouchWrapper`の`onPress`で、詳細画面の`TouchWrapper`の`display`を`normal`にすることで、画面を表示させます。
・ 二番目の`TouchWrapper`の`onPress`で、詳細画面の`TouchWrapper`の`display`を`invisible`にすることで、画面を非表示にします。

・ `Frame`は今回初めて使ってみましたが、背景色をつけるために使いました。
Frameの上にContainerを載せました。Frame単体では、Containerにあるような`alignItems`、`direction`、`justifyContent`がないためです。
なお、TouchWrapperやFrame、Containerすべてに`width`と`height`を設定したのは、明示的に画面全体を埋めて商品リストなどを誤ってタッチさせないためです。

##APLソースコード
出来上がったAPLのフルソースコードとデータJSONを載せます。実際にスキルで表示を試す場合は、[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)を参考しに実施します。

```json:APL
{
    "document": {
        "type": "APL",
        "version": "1.1",
        "settings": {},
        "theme": "dark",
        "import": [],
        "resources": [],
        "styles": {},
        "onMount": [],
        "graphics": {},
        "commands": {},
        "layouts": {},
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "type": "Container",
                    "items": [
                        {
                            "type": "Sequence",
                            "height": "100vh",
                            "data": "${payload.sample.sampleArray}",
                            "items": [
                                {
                                    "type": "TouchWrapper",
                                    "onPress": [
                                        {
                                            "type": "SetValue",
                                            "componentId": "msgBoxId",
                                            "property": "display",
                                            "value": "normal"
                                        },
                                        {
                                            "type": "SetValue",
                                            "componentId": "imageId",
                                            "property": "source",
                                            "value": "${data.imageURL}"
                                        },
                                        {
                                            "type": "SetValue",
                                            "componentId": "textId",
                                            "property": "text",
                                            "value": "${data.detail}"
                                        }
                                    ],
                                    "items": [
                                        {
                                            "type": "Container",
                                            "direction": "row",
                                            "items": [
                                                {
                                                    "type": "Image",
                                                    "width": "20vw",
                                                    "height": "20vh",
                                                    "source": "${data.imageURL}"
                                                },
                                                {
                                                    "type": "Text",
                                                    "text": "${data.text}"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "display": "invisible",
                            "type": "TouchWrapper",
                            "id": "msgBoxId",
                            "width": "100vw",
                            "height": "100vh",
                            "onPress": {
                                "type": "SetValue",
                                "componentId": "msgBoxId",
                                "property": "display",
                                "value": "invisible"
                            },
                            "item": [
                                {
                                    "type": "Frame",
                                    "width": "100vw",
                                    "height": "100vh",
                                    "items": [
                                        {
                                            "type": "Container",
                                            "width": "100vw",
                                            "height": "100vh",
                                            "alignItems": "center",
                                            "direction": "row",
                                            "justifyContent": "center",
                                            "item": [
                                                {
                                                    "type": "Image",
                                                    "id": "imageId",
                                                    "width": "50vw",
                                                    "height": "50vw"
                                                },
                                                {
                                                    "type": "Text",
                                                    "id": "textId",
                                                    "width": "50vw"
                                                }
                                            ]
                                        }
                                    ],
                                    "backgroundColor": "rgba(grey,1.0)"
                                }
                            ],
                            "position": "absolute"
                        }
                    ]
                }
            ]
        }
    },
    "datasources": {
        "sample": {
            "sampleArray": [
                {
                    "text": "コーヒー",
                    "detail": "コーヒーです。",
                    "imageURL": "https://coffee_480x480.jpg"
                },
                {
                    "text": "カプチーノ",
                    "detail": "カプチーノです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？",
                    "imageURL": "https://cappuccino_480x480.jpg"
                },
                {
                    "text": "カフェラテ",
                    "detail": "カフェラテです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？<br>カプチーノとはミルクの量が違う？",
                    "imageURL": "https://latte_480x480.jpg"
                },
                {
                    "text": "エスプレッソ",
                    "detail": "エスプレッソです。<br>加圧して抽出したもので、コーヒーよりもかなり濃いです。",
                    "imageURL": "https://espresso_480x480.jpg"
                }
            ]
        }
    }
}
```

#おわりに
今回はSetValueとFrameを使った画面レイアウトを紹介しました。
この方法はなかなか他のサイトでは記載されておらず、だいたいPagerを使って別のページに移るというのが多かったのですが、試してみましたら動きました。
Pagerも悪くはないとは思いますが、スワイプで画面が移動するのが自分が作成したいものとイメージと違っており、今回のレイアウトにしました。
Pagerはまだ使ったことがないので、またそのうち試してみます。