はじめに
Alexaを搭載した画面付きデバイスの画面レイアウトを作成します。
今回は、文字サイズや文字色などの文字装飾をリソースとスタイルを設定しながら実施します。
対象とするコンポーネントは、Textです。
スタイルは、HTMLで使用されるものとコンセプトは同じで、文字装飾などの設定をひとつのスタイルに定義して、その作成したスタイルをコンポーネントに設定するように使います。
例えば、「スタイルA」として、「文字は太字で色は赤色」と定義して、あるテキストに「スタイルA」を指定すると、そのテキストは「文字は太字で色は赤色」になるということです。
リソースは、その設定値などを定数化するものです。
例えば、「リソースA」として、「#ff0000」と定義して、あるプロパティで「@リソースA」を指定すると、そのプロパティの値は「#ff0000」になるということです。
今回実施する内容
Textの文字装飾のスタイルを作成し、Textにスタイルを設定します。スタイルを使うときにリソースも使います。
環境
OS:Windows 10 JP
Alexaスキル言語:Node.js
Editor:Visual Studio Code
APLバージョン:1.0, 1.1
参考
・Alexa ハローAPL、Alexaスキルの画面への対応
第1回のAlexa APLの記事です。タイトル通り、ハローAPLを表示させるだけのAPLです。
・Alexa APL, 第12回 文字サイズ、文字色
第12回のAlexa APLの記事です。TextにcolorやfontFamilyなどを直接設定して動作を確認する記事です。
・APLドキュメント リソース
AmazonのAPLドキュメントにあるリソースの説明です。
・APLドキュメント スタイル
AmazonのAPLドキュメントにあるスタイルの説明です。
・APLトレーニングシリーズ第2回: APLドキュメントの概要
AmazonのAlexa BlogsにAPLのレイアウト方法の記載がありました。
when
の使い方についてしれっと重要なことが書かれていました。
用語
APL
Alexa Presentation Language
amazonの画面つきのAlexaの画面表示用の言語。
JSONを使用した記載方法です。
インターネットのホームページはHTMLとCSSで作成しますが、AlexaはAPLで作成するということです。
APLオーサリングツール
APL作成を視覚的に見ながらAPLのJSONファイルを作成するツール。
サンプルテンプレートも準備されており、その中から選択していくだけで、だいたいの画面は作成できる。
スタイル
文字色、文字サイズ、フォントや背景色などのプロパティを集めた集合のこと。CSSなどで使うスタイルと意味は同じです。
前提条件
前提条件はとくにないといえばないですが、本まとめを読むにあたり、以下がわかっていることが前提です。
・alexa developer consoleのアカウントがある
・Alexaスキルを開発したことがある
・JSONの記載方法を知っている
・「Alexa ハローAPL、Alexaスキルの画面への対応」、および「Alexa APL, 第12回 文字サイズ、文字色」の記事をみている
今回使用するレイアウト
今回は、文字サイズや文字色などを変更して、その動きを確認します。
そのために基本となるレイアウトを以下の通り作成します。
「レイアウト画面」はこんな感じです。
- APLオーサリングツールを起動して「最初から作成」を選択する。
- 「レイアウト画面」の「mainTemplate」を選択し、「Container」を追加する。
- 「レイアウト画面」の「Container」を選択し、「Text」を追加する。
- 「レイアウト画面」の上で作成した「Text」を選択し、「詳細設定画面」で、以下を設定する。
・ text:${payload.sample.sampleArray[0].text}
5. 「レイアウト画面」の「Container」を選択し、「Text」を追加する。
6. 「レイアウト画面」の上で作成した「Text」を選択し、「詳細設定画面」で、以下を設定する。
・ text:${payload.sample.sampleArray[0].detail}
・ paddingLeft:10vw
7. 5, 6を3回繰り返す。sampleArrayの配列部分は1~3に設定する。
※今回は文字サイズや文字色を試すために、あえて配列をSequenceではなく、Textの繰り返しで設定しました。
JSONデータの作成
以下の通り、JSONデータを作成する。
{
"sample": {
"sampleArray": [
{
"text": "コーヒー(coffee)",
"detail": "コーヒー(coffee)です。",
"imageURL": "https://coffee_480x480.jpg"
},
{
"text": "カプチーノ(cappuccino)",
"detail": "カプチーノ(cappuccino)です。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的?",
"imageURL": "https://cappuccino_480x480.jpg"
},
{
"text": "カフェラテ(latte)",
"detail": "カフェラテ(latte)です。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的?<br>カプチーノとはミルクの量が違う?",
"imageURL": "https://latte_480x480.jpg"
},
{
"text": "エスプレッソ(espresso)",
"detail": "エスプレッソ(espresso)です。<br>加圧して抽出したもので、コーヒーよりもかなり濃いです。",
"imageURL": "https://espresso_480x480.jpg"
}
]
}
}
上記で作成した画面の確認
上記で作成した画面をみると、以下のようになります。
中型デバイス(Echo Show)
スタイルを使う
スタイルの作成(赤色+Bold)
まずは単純なモデルで、「コーヒー」や「カプチーノ」などを赤色の文字にしてBoldにするスタイルを作成します(配色は最悪ですが機能確認のためです)。
APLオーサリングツール上で、APLを開いて、"styles"に直接編集します。
以下のように記載します。
...
"styles": {
"menuNameStyle": {
"values": [
{
"color": "#ff0000",
"fontWeight": "bold"
}
]
}
},
...
スタイルはこれだけです。
簡単に説明します。
-
menuNameStyle
はスタイル名であり、自分で好きなものをつけることができます。 -
values
は配列で、複数記載でき、when
と組み合わせて状態によって、配列に記載したマッチするスタイルを変更できます。今回は一つだけ設定しました。 -
color
やfontWeight
でそのスタイルで使用する文字装飾を設定する。
スタイルの適用
APLオーサリングツール上で、以下のようにします。
- 「レイアウト画面」の上で作成した1番目の「Text」を選択し、「詳細設定画面」で、以下を設定する。
・ style:menuNameStyle
2. 1の内容を3、5、7番目の「Text」で同様に実施する。
スタイルは、Textに対して、ひとつを設定するだけで複数の文字装飾を一気に適用できるため、個別に設定するよりも手間が省けますし、統一感をもって設定できるため有用です。
whenをスタイルで使ってみる(要注意)
valuesが配列で設定し、when
を使って動作をわけられるということで動作を試してみます。
APLトレーニングシリーズ第2回: APLドキュメントの概要に、when
の使い方についてしれっと重要なことが書かれていました。
when プロパティは、リソースやスタイル、レイアウトなどで幅広く利用できます。 いずれも when プロパティが true のとき、そのオブジェクトが採択されますが、リソースやスタイルの配列では true になった後者の定義で上書きされるのに対し、レイアウトのコンポーネント配列では最初に true になったコンポーネントが採択されます。
要素 | 説明 |
---|---|
リソース、スタイル | 後者の定義で上書き。どんどん継承。 |
レイアウト | trueになった時点のコンポーネントが採択。 |
ということで、whenは使う場所によって、適用され方が違うのです。そんなに細かいレベルではなく大きな分類のためなれれば問題ないかと思いますが、最初勘違いしてスタイルが期待通り動かなかったため、記載しました。
では、小型デバイス用(Echo Spot)に、タイトルの色を緑色に変えます。
-
import
にalexa-viewport-profiles
を追加する。 -
menuNameStyle
のvalues
内を配列の2番目にwhen
を使って、小型デバイス(Echo Spot)用の識別をいれて、色を以下の通り緑色にする。
...
"import": [
{
"name": "alexa-viewport-profiles",
"version": "1.1.0"
}
],
...
"menuNameStyle": {
"values": [
{
"color": "#ff0000",
"fontWeight": "bold"
},
{
"when": "${viewport.shape == 'round'}",
"color": "#00ff00",
"fontWeight": "bold"
}
]
},
試した結果は以下です。小型デバイスだけ変更されます。
小型デバイス(Echo Spot)
whenを文字装飾内で使ってみる
スタイルを作っていて、Amazonの例を見ていて気付きましたが、whenはcolorなどの設定でも記載ができます。
三項演算子のような記載もできるようです。
では、小型デバイス用(Echo Spot)に、タイトルの色を緑色に変えます。
-
import
にalexa-viewport-profiles
を追加する。 -
menuNameStyle
のvalues
内を配列の2番目にwhen
を使って、小型デバイス(Echo Spot)用の識別をいれて、色を以下の通り緑色にする。
...
"import": [
{
"name": "alexa-viewport-profiles",
"version": "1.1.0"
}
],
...
"menuNameStyle": {
"values": [
{
"color": "${viewport.shape == 'round' ? '#00ff00' : '#ff0000'}",
"fontWeight": "bold"
}
]
},
上の「whenをスタイルで使ってみる(要注意)」に載せたものと同じ結果が得られます。
今回のようにcolor
を一か所だけ変更したいといった場合には、三項演算子のような記載もよいですが、感触的にはひとつだけではすまなさそうなため、上位でwhen
を使う前項の使い方のほうが良いかなと思いました。
もしくは、スタイル名を完全にデバイスごとに変えて作成するというのもありますが、スタイル名が長くなりそうですし、やはり一つのスタイル内でwhen
でわけるのがよさそうかなと思いました。
スタイルのプロパティ
スタイルのプロパティには、以下があります。
プロパティ | 型 | 説明 |
---|---|---|
description | 文字列 | スタイルの説明を記載します。自分への備忘。 |
extend | スタイル名の配列 | 継承元のスタイルの一覧。後のものが上書き。 |
values | valueオブジェクトの配列 | スタイルを設定するオブジェクトの配列。 |
スタイルの作成(extend)
extend
を使って、継承動作を確認します。
APLオーサリングツール上で、APLを開いて、"styles"に直接編集します。
以下のように記載します。
...
"styles": {
"menuNameStyle": {
"values": [
{
"color": "#ff0000",
"fontWeight": "bold"
}
]
},
"detailBase": {
"values": [
{
"color": "#00ff00",
"fontSize": "24dp"
}
]
},
"detailStyle": {
"extend": [
"detailBase"
],
"values": [
{
"color": "#0000ff",
"fontWeight": "bold"
}
]
}
},
...
図で説明します。
図の通りであり、extendは配列を設定できますが、複数設定するとどんどん上書きされるようです。
リソースを使う
リソースの作成(薄い黄色)
まずは単純なモデルで、薄い黄色のリソースを作成します。
APLオーサリングツール上で、APLを開いて、"resources"に直接編集します。
以下のように記載します。
...
"resources": [
{
"colors": {
"lghtYlw": "#ffff99",
"pnk": "#ff99ff"
}
}
],
...
リソースはこれだけです。
簡単に説明します。
-
colors
はリソースのプロパティ名であり、文字色に関する色を設定するためのものです。 -
lghtYlw
やpnk
はリソース名であり、自分で好きなものをつけることができます。 -
colors
はオブジェクトであり複数個設定できます。
リソースの適用
APLオーサリングツール上で、以下のようにします。
- APLを開いて、
menuNameStyle
のcolor
に@lghtYlw
を設定する。 -
detailStyle
のcolor
に@pnk
を設定する。
以下のようになります。
中型デバイス(Echo Show)
リソースのプロパティ
リソースのプロパティには、以下があります。
プロパティ | 型 | 説明 |
---|---|---|
description | 文字列 | スタイルの説明を記載します。自分への備忘。 |
boolean | ブール値のマップ | ブール値の名前をマッピング。 |
colors | 色のマップ | 色の名前のマッピング。 |
dimensions | ディメンションのマップ | ディメンションの名前のマッピング。 |
strings | 文字列の配列 | 名前を文字列にマッピング。 |
when | ブール値 | trueの場合にこのリソースを適用。 |
要するにboolean
、colors
、dimensions
、strings
の型名を指定して、その型の定数をその配下で定義するということです。
descriptionも説明を記載するだけのため、説明を割愛します。
whenを使ってみる
リソースにwhen
をつけてみます。
これをつけることで、同じ名前のリソースをwhen
でわけることができます。
では、小型デバイス用(Echo Spot)に、タイトルの色を赤色に変えます。
スタイルのところで作成したAPLに変更を加えます。
-
resources
のcolors
の下にもうひとつcolors
を追加する。そのとき、when
もつける。
...
"resources": [
{
"colors": {
"lghtYlw": "#ffff99",
"pnk": "#ff99ff" <=ピンク色を設定
}
},
{
"when": "${viewport.shape == 'round'}",
"colors": {
"pnk": "#ff0000" <=赤色を設定
}
}
],
...
これによって、以下のようになります。
小型デバイス(Echo Spot)
デバイスによるイメージの差分は、スタイルのwhen
を用いるか、リソースのwhen
を用いるか、どちらでも可能です。
どちらを用いるかは悩ましいですが、感覚的にはスタイルかなと思います。
リソースは値に名前を付けているものですが、名前はその値の特徴を示すものだと思います。
その特徴がデバイスの差分で違うというのは違和感があるため、スタイルでわけたほうが望ましいのかなと思いました。
といいつつも、dimensionsのような数値を相対的に設定する場合(例えば、中型デバイスは32dpだけど小型デバイスは24dpを使うなど)は、リソースでもいいなと思うので、悩ましいですね。
APLソースコード
出来上がったAPLのフルソースコードとデータJSONを載せます。実際にスキルで表示を試す場合は、Alexa ハローAPL、Alexaスキルの画面への対応を参考しに実施します。
{
"document": {
"type": "APL",
"version": "1.1",
"settings": {},
"theme": "dark",
"import": [
{
"name": "alexa-viewport-profiles",
"version": "1.1.0"
}
],
"resources": [
{
"colors": {
"lghtYlw": "#ffff99",
"pnk": "#ff99ff"
}
},
{
"when": "${viewport.shape == 'round'}",
"colors": {
"pnk": "#ff0000"
}
}
],
"styles": {
"menuNameStyle": {
"values": [
{
"color": "@lghtYlw",
"fontWeight": "bold"
},
{
"when": "${viewport.shape == 'round'}",
"color": "#00ff00",
"fontWeight": "bold"
}
]
},
"detailBase": {
"values": [
{
"color": "#00ff00",
"fontSize": "24dp"
}
]
},
"detailStyle": {
"extend": [
"detailBase"
],
"values": [
{
"color": "@pnk",
"fontWeight": "bold"
}
]
}
},
"onMount": [],
"graphics": {},
"commands": {},
"layouts": {},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"style": "menuNameStyle",
"text": "${payload.sample.sampleArray[0].text}"
},
{
"type": "Text",
"style": "detailStyle",
"paddingLeft": "10vw",
"text": "${payload.sample.sampleArray[0].detail}"
},
{
"type": "Text",
"style": "menuNameStyle",
"text": "${payload.sample.sampleArray[1].text}"
},
{
"type": "Text",
"style": "detailStyle",
"paddingLeft": "10vw",
"text": "${payload.sample.sampleArray[1].detail}"
},
{
"type": "Text",
"style": "menuNameStyle",
"text": "${payload.sample.sampleArray[2].text}"
},
{
"type": "Text",
"style": "detailStyle",
"paddingLeft": "10vw",
"text": "${payload.sample.sampleArray[2].detail}"
},
{
"type": "Text",
"style": "menuNameStyle",
"text": "${payload.sample.sampleArray[3].text}"
},
{
"type": "Text",
"style": "detailStyle",
"paddingLeft": "10vw",
"text": "${payload.sample.sampleArray[2].detail}"
}
]
}
]
}
},
"datasources": {
"sample": {
"sampleArray": [
{
"text": "コーヒー(coffee)",
"detail": "コーヒー(coffee)です。",
"imageURL": "https://coffee_480x480.jpg"
},
{
"text": "カプチーノ(cappuccino)",
"detail": "カプチーノ(cappuccino)です。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的?",
"imageURL": "https://cappuccino_480x480.jpg"
},
{
"text": "カフェラテ(latte)",
"detail": "カフェラテ(latte)です。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的?<br>カプチーノとはミルクの量が違う?",
"imageURL": "https://latte_480x480.jpg"
},
{
"text": "エスプレッソ(espresso)",
"detail": "エスプレッソ(espresso)です。<br>加圧して抽出したもので、コーヒーよりもかなり濃いです。",
"imageURL": "https://espresso_480x480.jpg"
}
]
}
}
}
おわりに
リソースとスタイルを使った文字装飾について記載しました。