[Alexa]stylesを使って押したら色が変わるボタンを作成する

# stylesを使うとうれしいこと
APLのドキュメント部では、layoutsやcommandsのように共通要素を外だしすることができます。
これと同様に、stylesを使用すると、コンポーンントの特定プロパティの値だけを取り出して定義・共通化することができます。
さらに、stylesでは「対象のコンポーネントが押下されたときだけ色を変える」といったことも可能です。
本記事では、APLでstylesを利用した例を挙げてみようと思います。

# APLドキュメントファイルの作成
以下は、stylesを利用したAPLドキュメントファイルの例です。
"styles"にてスタイル"pushButtonStyle"を定義し、Frame要素にて"pushButtonStyle"を適用しています。

``` StyleTestTemplate.json
{
    "type": "APL",
    "version": "1.3",
    "settings": {},
    "theme": "dark",
    "import": [],
    "resources": [],
    "styles": {
        "pushButtonStyle": {
            "value": [
                {
                    "backgroundColor": "#564387"
                },
                {
                    "when": "${state.pressed}",
                    "backgroundColor": "#ac8fee"
                },
                {
                    "when": "${state.focused}",
                    "borderColor": "#ffffff",
                    "botderWidth": 10
                }
            ]
        }
    },
    "onMount": [],
    "graphics": {},
    "commands": {},
    "layouts": {},
    "mainTemplate": {
        "parameters": [
            "payload"
        ],
        "items": [
            {
                "type": "Container",
                "width": "100vw",
                "height": "100vh",
                "alignItems": "center",
                "items": [
                    {
                        "type": "TouchWrapper",
                        "width": "50%",
                        "height": "20%",
                        "items": [
                            {
                                "type": "Frame",
                                "style": "pushButtonStyle",
                                "inheritParentState": true,
                                "width": "100%",
                                "height": "100%",
                                "items": [
                                    {
                                        "type": "Text",
                                        "width": "100%",
                                        "height": "100%",
                                        "textAlign": "center",
                                        "text": "色が変わるよ！",
                                        "textAlignVertical": "center"
                                    }
                                ],
                                "borderWidth": "2"
                            }
                        ]
                    }
                ],
                "justifyContent": "center"
            }
        ]
    }
}
```
こちらの例では、
　・普段は背景色が`#564387`
　・pressed時( = 押された時)は背景色が`#ac8fee`
　・focused時( =　フォーカスが合った時)は枠の色が`#ffffff`
というスタイルを定義し、Frameにセットしています。

上記jsonではFrameの"inheritParentState"がtrueに設定されており、親コンポーネントであるTouchWrapperの状態を継承するため、押された状態やフォーカスがあった時には色が変化します。

他に、styles関連でのポイントとしては以下あたりが挙げられます。

・スタイルには、[**こちら**](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-styled-properties.html)の「スタイル設定可能なプロパティ」に該当するプロパティのみ設定できる。
・上記に該当するプロパティであっても、コンポーネントが持っていないプロパティは反映されない。
　例：Containerに対して"backgroundColor"の値がセットされているスタイルを設定しても背景色は変わらない
・コンポーネントに直接値がセットされているプロパティは、スタイルに記載された設定よりも優先される。
　(→上記の例だと、Frameに直接backgroundColorの値をセットしてしまうと、StyleのbackgroundColorは機能しなくなる)

# Node.js実装例
Node.jsに実装すると、以下のような感じになります。
上記のStyleTestTemplate.jsonがaplフォルダ内に配置されている前提となります。

``` index.js
// 対話モデルにてStyleTestIntentを作成しておく
// StyleTestIntent発話時にこのハンドラに入る想定
const StyleTestIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'StyleTestIntent';
    },
    handle(handlerInput){
        let st = 'スタイルのテストです。';

        // APLドキュメントとデータソースを取得
        const StyleTestTemplate = require('./apl/StyleTestTemplate.json');

        // 画面作成 ※実際はAPL対応デバイスかどうかの確認が必要
        handlerInput.responseBuilder.addDirective({
            type: 'Alexa.Presentation.APL.RenderDocument',
            version: '1.0',
            document: StyleTestTemplate,
            datasources: {}        // データソース部不要のため空のオブジェクトをセット
        });

        return handlerInput.responseBuilder
            .speak(st)
            .reprompt(st)
            .getResponse();
    }
}

// 以下略…
```

この状態でスキルを実行すると、スタイル設定が反映されたボタンが画面に表示されると思います。
また、ボタンをタッチするとボタンの色が変わります。
![style.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354808/5ea1ceaa-1f23-102b-8e3c-fb69365010c9.gif)

# 補足
「focusedってどういう状態だよ、pressedは分かるけどフォーカスが合ってる状態ってなんだよ」と思う方もいるかもしれません。

FireTVからこのAPLで描写した画面を開いて見てみると、分かると思います。
FireTVをお持ちでない方向けに簡単に説明すると、
以下のような感じでリモコン操作のUIを構築することができます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">こういうこともできるって知ってた？<a href="https://twitter.com/hashtag/AlexaDevs?src=hash&amp;ref_src=twsrc%5Etfw">#AlexaDevs</a> <a href="https://twitter.com/hashtag/APL?src=hash&amp;ref_src=twsrc%5Etfw">#APL</a> <a href="https://t.co/XB8oPoRawi">pic.twitter.com/XB8oPoRawi</a></p>&mdash; イガラシさん (@IgarashisanT) <a href="https://twitter.com/IgarashisanT/status/1271755505124311040?ref_src=twsrc%5Etfw">June 13, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 参考URL

[APL Style Definition and Evaluation | Alexa Skills Kit](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-style-definition-and-evaluation.html)
[APLスタイル設定可能プロパティ | Alexa Skills Kit](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-styled-properties.html)