「はじめての Alexa Presentation Language (APL)」をご紹介しましたが、今回は、画面デザインを定義した部分(前回 homepage.json という名前で保存したもの)について概要を紹介します。
レイアウトとコンポーネント
APLでは画面デザインをJSONオブジェクトとして定義しますが、これを APLドキュメント と呼びます。homepage.json の中身を以下の簡単なものに置き換えてみてください。"こんにちは" というテキストとURLで指定された画像が、画面中央に縦に並んで表示されます。
{
"type": "APL",
"version": "1.0",
"mainTemplate": {
"item": {
"type": "Container",
"alignItems": "center",
"justifyContent": "center",
"width": "100vw",
"height": "100vh",
"items": [
{
"type": "Text",
"text": "こんにちは"
},
{
"type": "Image",
"source": "https://d2o906d8ln7ui1.cloudfront.net/images/cheeseskillicon.png",
"width": "120dp",
"height": "120dp"
}
]
}
}
}
type
と version
はお決まりです。APLでは、画面の定義を レイアウト、配置される各要素を コンポーネント と呼びますが、mainTemplate
の部分が最初に表示されるレイアウト、mainTemplate.item にコンポーネントを指定します。 例中では APL Text と APL Image コンポーネントを利用していますが、それぞれを JSONの object
として定義し、type
プロパティでコンポーネントの種類を指定します。その他利用できるコンポーネントの種類や各コンポーネントのプロパティなどの詳細は、 APLのコンポーネント を参照してください。 また、プロパティで扱う値に関しては、 APLのデータ型 を参照ください。
実はレイアウトは子コンポーネントを1つだけ持ちますので、複数のコンポーネントを配置する場合には APL Containerを利用します。横方向や縦方向にコンポーネントを並べて配置することもできますし、絶対値で指定の場所に配置することもできます。 また、APL Container はネストする形で、子 APL Container を含めることもできます。上下左右のパディング、アライメント、スペーシングなど細かに指定できますので、いろいろ試してみてください。
下例は Alexa DevSummit Tokyo 2018 公式スキル の画面ですが、コンポーネントを縦方向に配置してこのような画面を実装しています。
静的にコンポーネントを配置する APL Container 以外にも、動的データを配置するのに適した APL Sequenceや APL Pagerもあります。
パラメータとデータバインディング
パラメータとデータバインディングを使うことで、画面の内容に変化をつけることができます。 下の例は、mainTemplate のパラメータ payload
を定義して、 それを介してプログラムから データソース を受け取り、渡されたオブジェクトの内容をテキストとして表示するようにしたものです。
{
"type": "APL",
"version": "1.0",
"mainTemplate": {
"parameters": [
"payload"
],
"item": {
"type": "Text",
"text": "${payload.myData.title}",
"width": "100vw",
"height": "100vh",
"textAlign": "center",
"textAlignVertical": "center"
}
}
}
前回ご紹介した .addDirective() では、datasources
に data.json ファイルの中身を渡していましたが、代わりに、下のようにプログラム中で定義したオブジェクトを datasources
に渡してみます。 渡された "こんばんは" という文字を、APL Textの text
プロパティで ${payload.myData.title} として参照しています。 datasources
に渡すオブジェクトは、一つ以上のオブジェクト(下例では myData)を含むよう構成してください。
handle(handlerInput) {
const speechOutput = '画面サンプルです';
return handlerInput.responseBuilder
.speak(speechOutput)
.addDirective({
type : 'Alexa.Presentation.APL.RenderDocument',
version: '1.0',
document: require('./homepage.json'),
datasources: {
myData: {
title: 'こんばんは'
}
}
})
.getResponse();
},
このように参照値を含む式をプロパティ値として利用することを データバインディング と呼びます。
リソース、スタイル、条件式
下例では色値を colorTextPrimary という名前のリソースとして定義することで、以降、直接の色値の代わりに @colorTextPrimary という構文で共通して参照できるようになります。リソースは APLドキュメントの resources
で指定します。
また、 いくつかのプロパティ設定 をスタイルとして定義し、APLコンポーネントの style
プロパティに指定することで、同様のスタイルをもつ複数のAPLコンポーネントで定義を共有することができます。スタイルは APLドキュメントの styles
で定義します。
他にも レイアウトを再利用するしくみ (実は mainTemplate もレイアウトのひとつ)や、別ファイルで定義したドキュメントを インポートするしくみ などもあります。 リソースやスタイル・レイアウトなどを上手に使うことで、定義が簡単になるだけでなく、メンテナンス性に大きく影響しますので、是非ご活用ください。
また、例中の resources
の中に when
というプロパティがあります。式中の viewport
はスキルが動作するデバイスの特性を示すもので、この例では Echo Spot のような円形かどうかを検査して、テキストの色を変化させています。when
プロパティは、リソースやスタイル、レイアウトなどで幅広く利用できます。いずれも when
プロパティが true
のとき、そのオブジェクトが採択されますが、リソースやスタイルの配列では true
になった後者の定義で上書きされるのに対し、レイアウトのコンポーネント配列では最初に true
になったコンポーネントが採択されます。 詳しくは こちらをご参照ください。条件式を上手に使うことで、デバイスの特性やデータソースの状況に応じて、表示を最適化することができます。
{
"type": "APL",
"version": "1.0",
"resources": [
{
"colors": {
"colorTextPrimary": "#00FFFF"
}
},
{
"when": "${viewport.shape == 'round'}",
"colors": {
"colorTextPrimary": "#FF00FF"
}
}
],
"styles": {
"myTextStyle1": {
"values": {
"color": "@colorTextPrimary",
"fontStyle": "italic"
}
}
},
"mainTemplate": {
"item": {
"type": "Container",
"alignItems": "center",
"justifyContent": "center",
"width": "100vw",
"height": "100vh",
"items":[
{
"type": "Text",
"style": "myTextStyle1",
"text": "こんにちは"
},
{
"type": "Text",
"style": "myTextStyle1",
"text": "こんばんは"
}
]
}
}
}
今回のご紹介はここまでになります。APLドキュメントの全体像が見えてきましたでしょうか? できれば、前回の homepage.json がどのように定義されているのか、観察してみてください。 テンプレートのどこを変更すればどのような効果があるのか分かるようになったら、是非テンプレートのカスタマイズにもチャレンジしてみてください。
Source: Alexa