APLコマンド(1.4)
コマンドは、画面上のコンテンツの視覚および音声の表現を変更するメッセージです。発話への応答として、コマンドとAlexa.Presentation.APL.ExecuteCommands
ディレクティブをデバイスに送信します。ボタン押下への応答など、APLドキュメントのイベントハンドラーを使って、コマンドを直接トリガーします。
具体的なコマンドについては、APL標準コマンドとAPLメディアコマンドを参照してください。
コマンドと画面アクション
コマンドがサポートするシーンでのアクションには、次のタイプがあります。
- シーン内をナビゲートする
ScrollView
またはSequence
をスクロールする- スクロールしてコンポーネントを表示する
Pager
で表示されるページを変更する
- 既存シーン内でコンポーネントを変更する
- 入力コントロールを更新して新しい状態を反映する
- 既存コンポーネントの表示を変更する
- 既存のシーン内でビデオクリップを再生/一時停止する
- 音声
- 単一コンポーネントのオーディオコンテンツを読む
- 2つ以上のコンポーネントのオーディオコンテンツを読む
- APL Extensionにコマンドを送信する
コマンド実行の概要
このセクションでは、イベントハンドラーまたは外部で生成されたコマンドによって開始されたコマンドの実行に使用するアルゴリズムの概要を説明します。
通常モードまたは高速モードで連続して実行されるコマンドの配列を例とします。
通常モードの評価
通常モードで実行するコマンドには、名前付きのシーケンサーが必要です。「メイン」のシーケンサー上で、別のシーケンサーに割り当てられるか、SequentialまたはParallelのサブコマンドであるかのいずれにも当てはまらない場合、デフォルトで実行されるコマンドです。
配列の各コマンドについて、以下が順に実行されます。
-
コマンドの
when
プロパティを評価します。false
と評価された場合は、現在のコマンドをスキップして配列内の次のコマンドに進みます。 -
コマンドの
delay
プロパティを評価します。0より大きい場合は、ミリ秒単位で指定時間の間、一時停止します。 -
コマンドの
sequencer
プロパティをチェックします。現在のシーケンサーと同じ値の場合、このコマンドを適切なシーケンサーに渡して、配列内の次のコマンドに進みます。 -
コマンドの
type
プロパティを評価します。type
が認識できない場合、配列内の次のコマンドに進みます。有効な
type
値には、次のものがあります。- SendEventなどのビルトインコマンド。すべての必須コマンドプロパティに値がある場合、コマンドを実行します。一部のコマンドはただちに返されます。コマンドが実行を終了するまでシーケンサーを一時停止するコマンドもあります。
- ユーザー定義コマンド。ユーザー定義コマンドは、実行するコマンドの配列内にインフレートされ、このセクションのルールに従ってこれらのコマンドを実行してすべてのコマンドの実行が終了したら次に進みます。
- Extensionコマンド。コマンドを実行します。一部のextensionコマンドはすぐに返されます。コマンドが実行を終了するまでシーケンサーを一時停止するコマンドもあります。
高速モードの評価
fast mode
で実行されるコマンドには、名前付きのsequencer
がありません。配列の各コマンドについて、以下が順に実行されます。
-
コマンドの
when
プロパティを評価します。false
と評価された場合は、現在のコマンドをスキップして配列内の次のコマンドに進みます。 -
コマンドの
sequencer
プロパティをチェックします。値がある場合、このコマンドを適切なシーケンサーに渡して、配列内の次のコマンドに進みます。渡されたコマンドは、高速モードではなく通常モードで実行されます。 -
コマンドの
type
プロパティを評価します。type
が認識できない場合、配列内の次のコマンドに進みます。有効な
type
値には、次のものがあります。- SetValueなど、高速モードをサポートするビルトインコマンド。すべての必須コマンドプロパティに設定されている場合、コマンドを実行します。高速モードをサポートするコマンドの一覧については、高速モードのコマンドを参照してください。
- SendEventなど、高速モードをサポートしないビルトインコマンド。コマンドをスキップします。
- ユーザー定義コマンド。ユーザー定義コマンドは、実行するコマンドの配列内にインフレートされ、このセクションのルールに従ってこれらのコマンドを実行してすべてのコマンドの実行が終了したら次に進みます。
- 高速モードをサポートするextensionコマンド。コマンドを実行します。
- 高速モードをサポートしないextensionコマンド。コマンドをスキップします。
コマンドの評価
コマンドの個々のプロパティはデータバインディングをサポートします。コマンドのデータバインディングコンテキストには、コマンドが定義されたコンテキスト、コマンドがトリガーされる状況に関する情報を含むevent
プロパティによって拡張されたコンテキスト、コマンドの対象となるコンポーネントがあります。
イベントの内容
コマンドはソースデータのバインディングコンテキストで評価を行います。
ExecuteCommands
ディレクティブによってデバイスに送信されたコマンドが、最上位レベルのデータバインディングコンテキストで評価されます。名前付きリソースと共にviewport
プロパティとenvironment
プロパティを含むデータバインディングコンテキストです。
画面タッチなどのAPLのイベントに応答して発行されたコマンドは、コマンドが定義されているローカルのデータバインディングコンテキストで評価を行います。
次にTouchWrapper
のサンプルを示します。
{
"type": "TouchWrapper",
"bind": [
"name": "myRandomData",
"value": 24.3
],
"onPress": {
"type": "SendEvent",
"arguments": [ "値は${myRandomData}です" ]
}
}
TouchWrapperを押すと、最初の引数は「値は24.3です」と設定されます。
eventプロパティ
ソースデータのバインディングコンテキストは、コマンドが評価を行うときにイベントデータによって拡張されます。このイベントデータには、event
プロパティ内でアクセスします。
eventプロパティには、event.source
とevent.target
という2つの主要サブプロパティがあります。
event.source
プロパティには、イベントを発生させたコンポーネントに関してシステムから提供される情報が含まれます。event.target
プロパティには、イベントを受け取るコンポーネントに関してシステムから提供される情報が含まれます(該当する場合)。
event.target
プロパティがないコマンドもあります。たとえば、SendEvent
コマンドには、event.target
プロパティがありません。event.source
プロパティはすべてのコマンドに存在します。event.source
の詳細はそれぞれ異なるため、コンポーネントを表すとは限りません。たとえば、ソースがコンポーネントではなく、extensionの場合もあります。
データバインディングコンテキストに追加されるevent
プロパティの形式は、次のとおりです。
"event": {
"source": { // 常に存在します
"type": "COMPONENT_TYPE", // コンポーネントの型または"Document"
"handler": "EVENT_HANDLER", // イベントハンドラーの名前(コマンドのメモを参照してください)
"id": "SOURCE_ID", // ソースコンポーネントのID
"uid": "SOURCE_UID", // ソースコンポーネントのUID
... // 追加のソースコンポーネントプロパティ
},
"target": { // コマンドにコンポーネントターゲットがある場合にのみ存在します
"type": "COMPONENT_TYPE", // ターゲットコンポーネントの型
"id": "TARGET_ID", // ターゲットコンポーネントのID
"uid": "TARGET_UID", // ターゲットコンポーネントのUID
... // 追加のターゲットコンポーネントプロパティ
},
... // コマンド固有のプロパティ
}
event.source
プロパティにはhandler
プロパティがありますが、event.target
プロパティにはありません。
以下の表は、さまざまなコンポーネントがレポートする標準のevent.source
プロパティとevent.target
プロパティの一覧です。特定のコンポーネントのプロパティに関するドキュメント全文については、各コンポーネントのドキュメントを参照してください。
プロパティ | 型 | 説明 | レポート元 |
---|---|---|---|
bind |
マップ | データバインディングコンテキスト | コンポーネント |
checked |
ブール値 | チェックの状態 | コンポーネント |
color |
色 | 現在の色 | Text |
currentTime |
整数 | 現在の再生位置 | Video |
disabled |
ブール値 | 無効にされた状態 | コンポーネント |
duration |
整数 | 現在のビデオの長さ(ミリ秒) | Video |
ended |
ブール値 | ビデオが終了している場合はTrue | Video |
focused |
ブール値 | フォーカス状態 | コンポーネント |
height |
数値 | 高さ(dp) | コンポーネント |
id |
文字列 | コンポーネントID | コンポーネント |
opacity |
数値 | ローカル不透明度(累積値ではない) | コンポーネント |
page |
整数 | 現在表示されているページ | Pager |
paused |
ブール値 | ビデオが一時停止している場合はtrue | Video |
position |
数値 | スクロール距離の割合 | Sequence 、ScrollView |
pressed |
ブール値 | 押された状態 | コンポーネント |
text |
文字列 | 表示されるテキスト | Text |
trackCount |
整数 | トラック数 | Video |
trackIndex |
整数 | 現在のトラックのインデックス | Video |
type |
文字列 | コンポーネントタイプ("Frame"など) | コンポーネント |
uid |
文字列 | ランタイムで生成された固有ID | コンポーネント |
url |
文字列 | ソースURL | Image 、VectorGraphic 、Video |
width |
数値 | 幅(dp) | コンポーネント |
bind
プロパティは、コンポーネントのデータバインディングコンテキストへのアクセスを提供します。次の例は、バインドされた値へのアクセス方法を示しています。IDがMyText
のコンポーネントが、SetValue
コマンドのターゲットです。このため、event.target.bind
プロパティには、MyText
コンポーネントにバインドされたデータが含まれ、コマンドはその値を使用できます。
[
{
"type": "TouchWrapper",
"onPress": {
"type": "SetValue",
"componentId": "MyText",
"property": "text",
"value": "今日の単語は${event.target.bind.WordOfTheDay}です"
},
"items": [
{
"type": "Text",
"text": "クリックして"
}
]
},
{
"type": "Text",
"bind": [
{
"name": "WordOfTheDay",
"value": "熊"
}
],
"id": "MyText"
}
]
event.source
event
のevent.source
プロパティには、イベントをトリガーした状況に関するメタ情報が含まれます。APLランタイムはevent.source
を生成し、ドキュメントでこの情報を使用できます。event.source
プロパティには、すべての標準プロパティと以下の項目が含まれます。
プロパティ | 型 | 説明 |
---|---|---|
handler | 文字列 | このメッセージを開始したイベントハンドラーの名前です。たとえば、「Press」や「Checked」です。 |
value | 任意 | このメッセージを開始したコンポーネントの値です。 |
event.source.value
プロパティは、コンポーネントによって異なります。たとえば、TouchWrapper
の場合、event.source.value
には、コンポーネントチェックの状態が含まれます。ScrollView
の場合、プロパティにはスクロール位置が含まれます。提供される特定のevent.source.value
プロパティについては、個々のコンポーネントの定義を参照してください。
event.source.value
プロパティは廃止されていますので、使用しないでください。代わりに、各コンポーネントに直接ドキュメント化されたプロパティを使用してください。たとえば、TouchWrapper
のチェック状態の場合、event.source.value
の代わりにevent.source.checked
を使用します。APLの以前のバージョンとの下位互換性のため、event.source
プロパティにはtype
プロパティと同じsource
サブプロパティも含まれています。つまり、${event.source.source == event.source.type}
となります。event.source.source
は廃止されているため、使用しないでください。
event.target
event.target
プロパティは、イベントを受け取るコンポーネントについての状態情報を提供します。target
の値は、コンポーネントによって異なります。想定されるtarget
の値については、個々のコンポーネントの定義を参照してください。
APLの以前のバージョンとの下位互換性のため、イベントのtargetプロパティは、Image
、VectorGraphic
、Video
コンポーネントのurlプロパティと同じ、source
サブプロパティについても報告します。つまり、${event.target.source == event.target.url}
となります。event.target.source
は廃止されているため、使用しないでください。
評価に関する注意
- ほとんどのコマンドはターゲットとしてcomponentIdを取得します。コマンド自体がターゲットの場合は、
componentId
を省略できます。 ExecuteCommands
ディレクティブを使ってデバイスにコマンドを送信する場合は、必ずcomponentIdを指定する必要があります。- コマンドに
componentId
プロパティが含まれる場合、この値を使って、ツリー階層のルートからすべてのコンポーネントを深さ優先検索で検索し、値と一致した最初のコンポーネントを返します。コマンドが正しいコンポーネントをターゲットにしていることを保証するには、以下のいずれかを実行します。id
プロパティを持つターゲットコンポーネントに一意の値を割り当て、コマンドのcomponentId
をその値に設定します。- 視覚コンテキストで提供される、システムが生成した
uid
プロパティ値を使用します。
- コマンドのデータバインディング式は、コマンドを定義するときではなく、実行するときに評価されます。たとえば、ExecuteCommandsディレクティブが、グローバルデータバインディングコンテキストを参照するデータバインディング式を含んでいる可能性があります。これらの式は、デバイスでコマンドが実行されたときに評価されます。コマンドがクラウドで作成されたときではありません。
- イベントハンドラーとExecuteCommandsディレクティブが、実行するコマンドの配列を取り出します。この配列は、repeatCountが0である
Sequential
コマンドとまったく同じように扱われます。
コマンドのシーケンス実行
コマンドはAPLランタイム環境で実行されます。ユーザーと環境のアクションが、実行するコマンドをトリガーします。Parallel
コマンドとSequential
コマンドも、実行するコマンドのセットをトリガーします。コマンドのシーケンス実行ルールによって、複数のコマンドが同時に実行される場合の動作が決まります。ルールがないと、コマンドが競合してしまうため、このルールは必要です。コマンドの定義方法に基づいて、この動作の一部を制御することができます。
このセクションでは次の用語を使用します。
- リソース – コマンドが本来使用するもので、別のコマンドと共有することはできません。テキスト読み上げのコマンドは、"speech"リソースを使用します。一定の時間、特定のコンポーネント上で動作するコマンド(AnimateItemなど)の場合は、そのコンポーネントがリソースとなります。
- 通常モード – コマンドを実行する標準の方法です。ほとんどのコマンドは、通常モードでのみ実行されます。通常モードのコマンドは、実行に時間がかかる場合があります。
- 高速モード – コマンドを実行するもう1つの方法です。実行に時間のかかるコマンドが適切でない場合に使用します。高速モードでは、すべての遅延とほとんどのコマンドが無視されます。高速モードは、onScrollなどのイベントハンドラーで使用されます。ここでは、イベントハンドラーが1秒間に何度も起動されます。
- シーケンサー – 1つのコマンドを同時に実行できる名前付きのエンティティです。
normal mode
で実行されるコマンドはそれぞれ、名前付きシーケンサーに関連付けられます。シーケンサーの指定には、command_sequencer_property
プロパティを使用します。 - サブコマンド – 別のコマンド内に含まれるコマンド(
parallel_command
またはsequential_command
)です。サブコマンドの階層は、「コマンドツリー」と呼ばれることもあります。
コマンドのシーケンス実行ルール
APLランタイムは、コマンドをシーケンス実行する際、次のルールを使用します。
- 通常モードのコマンドはすべて、1つのシーケンサー上で実行されます。そのシーケンサーが既にコマンドを実行している場合、それらのコマンドは終了し、新しいコマンドが実行されます。
- 高速モードのコマンドはシーケンサーを使用しません。
- シーケンサーを明示的に指定するコマンドはすべて、通常モードで実行されます。
- サブコマンドは、サブコマンドが明示的にシーケンサーを指定しない限り、親コマンドと同じシーケンサー上で実行されます。サブコマンドがシーケンサーを指定している場合、ランタイムはそのコマンドをシーケンサーに引き渡して、親コマンド内でそのコマンドを完了とマークします。
- デフォルトのシーケンサー名は、「MAIN」です。サブコマンド以外の通常モードコマンドが明示的にシーケンサーを指定しない場合、コマンドは「MAIN」シーケンサーで実行されます。通常モードのサブコマンドは、ルール4に従います。
- 画面タッチやキーボード入力など、ユーザーが何らかのデバイス操作を行うと、「MAIN」
sequencer
で実行されているコマンドはすべて終了します。 - コマンドが実行を開始すると、新しいコマンドで必要な
resource
を使用している現在実行中のコマンドは、すべて終了します。
たとえば、ユーザーが画面上のボタンをタッチしたとします。この操作によって、「MAIN」シーケンサー上で次のような一連のコマンドが開始されます。
- 画面上の変化をアニメーション化します。
- 特定の位置までリストを下にスクロールします。
- 項目を読み上げます。
ユーザーは、画面をもう一度タッチすることで、この一連のコマンドをいつでも中断できます。ユーザーが画面をタッチすると、「MAIN」シーケンサーが現在実行中のコマンドを終了します。
デフォルトのシーケンス実行動作を上書きするには、シーケンサーを直接指定できます。この手法を使うと、コマンドを並行して実行できます。シーケンス実行動作を変更するシナリオには、次のような場合が考えられます。
- 通常は高速モードで実行されるイベントハンドラーを使って、通常モードのコマンドを実行したい場合。たとえば、
ScrollView
コンポーネントのonScroll
イベントハンドラーで、SendEvent
コマンドを実行したいとします。通常、onScroll
ハンドラーは、通常モードのコマンドを無視します。この場合、SendEvent
上でシーケンサー名を指定すると、ハンドラーに強制的に通常モードを使用させることができるため、SendEvent
が実行されます。 - 通常のユーザー対話動作を上書きして、ユーザーが画面をタッチしてもコマンドの実行を続けたい場合。たとえば、子ども用ゲームの画面上コンポーネントをアニメーション化する
AnimateItem
コマンドで、画面がタッチされてもアニメーションを停止させたくない場合などです。 - 複数コンポーネントのアニメーションがトリガーされた場合、新しいコンポーネントを表示して古いコンポーネントを非表示にします。
リソース
各コマンドは、実行の際に1つ以上のシステムリソースを使用できます。シーケンサールールで定義されているように、特定のリソースを使用するコマンドは1回に1つしか実行できません。そのリソースを必要とする新しいコマンドが実行を開始すると、古いコマンドは終了します。
以下は、リソースと、そのリソースを使用するコマンドの一覧です。
- フォアグラウンドオーディオ再生
SpeakItem
SpeakList
PlayMedia
(フォアグラウンドのオーディオトラックを使用する場合)ControlMedia
(フォアグラウンドのオーディオトラックでplay
コマンドを実行する場合)
- バックグラウンドオーディオ再生
PlayMedia
(バックグラウンドのオーディオトラックを使用する場合)ControlMedia
(バックグラウンドのオーディオトラックでplay
コマンドを実行する場合)
- スクロール位置(スクロールコンポーネントによって、
ScrollView
、Sequence
のどちらか) - ページャー位置(
Pager
コンポーネント) - コンポーネントアニメーション(コンポーネントプロパティのアニメーション化)
SpeakItem
とSpeakList
は、複数リソースを使用できます。
通常モード
APLランタイムは、次のシナリオではコマンドを通常モードで実行します。
- ドキュメントが最初に読み込まれるとき(ドキュメントの
onMount
およびコンポーネントのonMount
)。 - ユーザーがタッチまたは
TouchWrapper
を選択したとき(onPress
)。 - ユーザーが
Pager
上でスワイプして表示されるページが変わったとき(onPageChanged
)。 - ビデオコンポーネントがビデオの再生を終了するか、トラックを変更したとき(
onEnd
、onPause
、onPlay
、onTrackUpdate
)。 - ExecuteCommandディレクティブまたはextensionイベントハンドラーなどの外部ソースから新しいコマンドセットを受信したとき。
- ユーザーがキーボードのキーを押したり、放したりしたとき(
handleKeyDown
およびhandleKeyUp
)。
デフォルトでは、すべての通常モードコマンドが「MAIN」シーケンサーを使用します。
次の例では、onPressイベントハンドラーにコマンド配列があります。この配列は、シーケンス実行される配列として扱われます。このため、SpeakItem
が最初に実行されます。読み上げが完了すると、Scroll
コマンドが実行されます。Scroll
が完了すると、SendEvent
コマンドが実行され、スキルにUserEvent
が送信されます。これらのコマンドはすべて、「MAIN」シーケンサー上で実行されます。
{
"type": "TouchWrapper",
"items": {
"type": "Text",
"id": "myText",
"speech": "読み上げる値"
},
"onPress": [
{
"type": "SpeakItem",
"componentId": "myText"
},
{
"type": "Scroll",
"componentId": "myScrollRegion",
"distance": 2
},
{
"type": "SendEvent",
"arguments": [
"ボタンが押されたので読み上げました"
]
}
]
}
上の例では、Scroll
コマンドを実行するコンポーネントがスクロールイベントを生成し、コンポーネントのonScrollイベントハンドラーで定義されたコマンドを呼び出すことができます。これらのコマンドは高速モードで実行されるため、現在実行中のコマンドシーケンスに影響しません。
ユーザーがTouchWrapper
を複数回タップすると、コマンドシーケンスは終了し、タップごとに再開します。onPress
ハンドラーを設定してTouchWrapper
を無効にすることもできますが、これでは問題を解決できません。ユーザーが画面をタップすると、「MAIN」シーケンサー上のコマンドは必ず終了します。
代わりに、コマンドに別のシーケンサーを割り当てることで、コマンドのシーケンス実行が完了することを保証できます。次の例はいずれも、TouchWrapper
を無効にして、シーケンス実行が終了して別のシーケンサーを使用するまでシーケンス実行を再開できないようにしています。これにより、画面をタッチしても、コマンドがキャンセルされません。
{
"type": "TouchWrapper",
"items": {
"type": "Text",
"id": "myText",
"speech": "読み上げる値"
},
"onPress": [
{
"type": "Sequential",
"sequencer": "MySequencer",
"commands": [
{
"type": "SetState",
"state": "disabled",
"value": true
},
{
"type": "SpeakItem",
"componentId": "myText"
},
{
"type": "Scroll",
"componentId": "myScrollRegion",
"distance": 2
},
{
"type": "SendEvent",
"arguments": [
"ボタンが押されたので読み上げました"
]
}
],
"finally": {
"type": "SetState",
"state": "disabled",
"value": false
}
}
]
}
カスタムの"MySequencer"は「MAIN」のシーケンサーではないため、画面がもう一度タッチされてもコマンドはキャンセルされません。この例では、最後のSetState
コマンドがfinally
ブロックで実行されていることに注意してください。何らかの理由でSequential
が終了しても、finally
で指定されたコマンドは実行され、TouchWrapper
を再度有効にします。
前の例は、すべてのコマンドがSequential
のサブコマンドであったことから、一連のコマンドで機能しました。シーケンサールールでは、サブコマンドは独自のシーケンサーを指定しない限り、親と同じシーケンサー上で実行されます。
一方、onPress
に割り当てられた以下のコマンド配列は機能しません。ユーザーがこのTouchWrapper
をタップしても、何も起こりません。
{
"type": "TouchWrapper",
"items": {
"type": "Text",
"id": "myText",
"speech": "読み上げる値"
},
"onPress": [
{
"type": "SetState",
"state": "disabled",
"value": true,
"sequencer": "BadIdea"
},
{
"type": "SpeakItem",
"componentId": "myText",
"sequencer": "BadIdea"
},
{
"type": "Scroll",
"componentId": "myScrollRegion",
"distance": 2,
"sequencer": "BadIdea"
},
{
"type": "SendEvent",
"arguments": [
"ボタンが押されたので読み上げました"
],
"sequencer": "BadIdea"
},
{
"type": "SetState",
"state": "disabled",
"value": false,
"sequencer": "BadIdea"
}
]
}
onPress
コマンドはデフォルトでMAINシーケンサー上で実行されるため、この例は失敗します。別のシーケンサーを指定すると、ハンドラーはコマンドを別のシーケンサーに引き渡して、配列内の「次の」コマンドを実行します。シーケンサーが新しいコマンドを受け取ると、既存のコマンドはすべて終了し、新しいコマンドで置き換えられます。
失敗する例のイベントシーケンスは、次のようになります。
onPress
ハンドラーは、SetState
をBadIdea
シーケンサーに引き渡します。onPress
ハンドラーがSpeakItem
に進み、すぐにSpeakItem
をBadIdea
に引き渡します。BadIdea
シーケンサーは、SetState
をキャンセルし、SpeakItem
を開始します。onPress
ハンドラーは、SendEvent
をBadIdea
に引き渡します。BadIdea
シーケンサーは、SpeakItem
をキャンセルし、SendEvent
を開始します。onPress
ハンドラーは、SetState
をBadIdea
に引き渡します。BadIdea
シーケンサーは、SendEvent
をキャンセルし、SetState
を開始します。SetState
コマンドは正常に実行されますが、TouchWrapper
が既に有効になっているため何も起こりません。
Sequential
コマンド内部に配置し、新しいシーケンサーをSequential
コマンドに割り当てるようにしてください。シーケンサーを使って、コマンドを実行するかしないかを切り替えることもできます。次の例では、最初のTouchWrapper
がAnimateItem
コマンドを実行して、ボールの動きをアニメーション化します。2つ目のTouchWrapper
が、AnimateItem
コマンドをキャンセルする新しいコマンドを同じシーケンサーに送ることで、アニメーションを強制的に停止させます。
{
"type": "Container",
"direction": "row",
"items": [
{
"type": "Frame",
"id": "Ball",
"width": 100,
"height": 100,
"borderRadius": 50,
"backgroundColor": "red"
},
{
"type": "TouchWrapper",
"items": {
"type": "Text",
"text": “移動を開始”
},
"onPress": [
{
"type": "AnimateItem",
"easing": "ease-in-out",
"duration": 1000,
"repeatCount": 10000000,
"repeateMode": "reverse",
"componentId": "Ball",
"sequencer": "BallSequencer",
"value": {
"property": "transform",
"from": {
"translateY": 0
},
"to": {
"translateY": 300
}
}
}
]
},
{
"type": "TouchWrapper",
"items": {
"type": "Text",
"text": “移動を停止”
},
"onPress": [
{
"type": "Idle",
"sequencer": "BallSequencer"
}
]
}
]
}
2つ目のTouchWrapper
のonPress
ハンドラーは、BallSequencer
上でIdle
コマンドを実行し、AnimateItem
を終了します。Idle
コマンドは何もしませんが、シーケンサー上で現在実行中のコマンドをすべて終了します。BallSequencer
に送信されたほかのコマンドもすべて、同じ結果になります。
高速モード
イベントハンドラーの中には、1秒間に何回もトリガーできるものもあります。たとえば、ScrollView
上のonScroll
ハンドラーは、スクロール位置が移動するたびに起動します。同時に、実行に時間がかかるコマンドもあります。たとえば、画面上のリストのスクロールやテキストの読み上げといったコマンドです。
頻繁に起動されるイベントハンドラーから時間のかかるコマンドを実行することによる問題を回避するため、こうしたハンドラーはコマンドを「高速モード」で実行します。
フレームレートで実行されるイベントハンドラーからトリガーされるコマンドのセットはすべて、「高速」モードを使用します。それ以外のコマンドのシーケンスは、すべて通常モードで実行されます。高速モードでは、ハンドラーはコマンドのすべての「遅延」設定を無視し、実行に時間がかかるコマンドをスキップします。イベントハンドラーは次のように動作します。
イベントハンドラー | 動作 |
---|---|
アクション可能なonBlur |
高速モード |
アクション可能なonFocus |
高速モード |
アクション可能なhandleKeyDown |
通常モード |
アクション可能なhandleKeyUP |
通常モード |
コンポーネントのonCursorEnter |
高速モード |
コンポーネントのonCursorExit |
高速モード |
コンポーネントのonMount |
通常モード |
ドキュメントのonMount |
通常モード |
PagerのonPageChanged |
通常モード/高速モード |
ScrollViewのonScroll |
高速モード |
SequenceのonScroll |
高速モード |
タッチ可能なonDown |
高速モード |
タッチ可能なonMove |
高速モード |
タッチ可能なonUp |
高速モード |
タッチ可能なonPress |
通常モード |
VideoのonEnd |
通常モード/高速モード |
VideoのonPause |
通常モード/高速モード |
VideoのonPlay |
通常モード/高速モード |
VideoのonTimeUpdate |
高速モード |
VideoのonTrackUpdate |
通常モード/高速モード |
ユーザーの操作(TouchWrapper
をタップするなど)によって発生する1回限りのイベントは、常に通常モードで実行されます。スクロールや時間の更新などのイベントは、高速モードで実行されます。いずれのモードでも、実行できるイベントは通常のアクション(ビデオトラックの終了など)または最終的に高速モードでトリガーされたコマンド(スクロールイベントによるビデオの一時停止など)によってトリガーされます。外部コマンドおよびextensionコマンドは通常モードで実行されます。
各コマンドの説明には、高速モードでの動作が記載されています。次の表は、高速モードの動作をまとめたものです。
コマンド | 高速モードの動作 |
---|---|
Idle |
無視されます。 |
Sequential |
実行されます。 |
Parallel |
実行されます。 |
SendEvent |
無視されます。 |
SetValue |
実行されます。 |
SetState |
実行されます。 |
SetFocus |
実行されます。 |
ClearFocus |
実行されます。 |
SpeakItem |
無視されます。 |
SpeakList |
無視されます。 |
Scroll |
無視されます。 |
ScrollToIndex |
無視されます。 |
ScrollToComponent |
無視されます。 |
SetPage |
無視されます。 |
AutoPage |
無視されます。 |
PlayMedia |
無視されます。 |
ControlMedia |
command="play" の場合は無視されます。それ以外の場合は実行されます。 |
OpenUrl |
無視されます。 |
AnimateItem |
終了状態にジャンプします。 |
Finsih |
実行されます。 |
Select |
実行されます。 |
sequencer
プロパティに値を設定して高速モードで実行されるコマンドはすべて、指定されたシーケンサーに引き渡され、通常モードで実行されます。この機能を使って、高速モードのイベントハンドラーから通常モードのコマンドを実行します。
以下の例は、スクロール表示の位置が移動するたびにその位置をチェックし、スクロール位置が最上部に来たらイベントを送信します。イベント送信にかかった時間を記録することでレート制限を適用し、イベント間が少なくとも1秒以上空くようにします。sequencer
プロパティがない場合、SendEvent
は実行されません。
{
"type": "ScrollView",
"bind": [
{
"name": "LastEventSentTime",
"value": 0
}
],
"onScroll": [
{
"type": "Sequential",
"when": "${event.source.value == 0 && utcTime > LastEventSentTime + 1000}",
"commands": [
{
"type": "SetValue",
"property": "LastEventSentTime",
"value": "${utcTime}"
},
{
"type": "SendEvent",
"arguments": [
"スクロールが最上部に到達しました"
],
"sequencer": "ScrollSender"
}
]
}
]
}
コマンドツリー
コマンドツリーとは、実行される一連のコマンドのことです。コマンドツリーが発生するのは、コマンドがネストされている場合や、あるコマンドによって新しいイベントハンドラーが起動される場合です。次のようなプリミティブコマンドに、ネストされたコマンドが含まれます。
Parallel
Sequential
OpenURL
ユーザー定義のコマンドもコマンドのネストをサポートします。
プリミティブコマンドもイベントハンドラーをトリガーできます。たとえば、Scroll
のScrollToComponent
、SpeakList
コマンドは、すべてonScroll
イベントハンドラーを呼び出すことができます。
コマンドツリーは最後まで実行することも、途中で終了することもできます。コマンドツリーを終了すると、直ちにすべてのコマンドの実行が中止されます。ソースはコマンドツリーの実行をトリガーします。その後、コマンドツリーは途中で終了されない限り、最後まで実行されます。
次の例は、Scroll
、SpeakItem
、PlayVideo
コマンドを含むExecuteCommands
ディレクティブのコマンドツリーを示しています。
ExecuteCommand
+ Scroll (distance=-10000) // 上方向にスクロールする
+ onScroll // 一番上までスクロールするたびに起動される
+ SetValue (name="opacity", value=event.source.value * 10) // 不透明度を変更する
+ SpeakItem (id) // 項目をスクロールして表示させ、カラオケ状態にする
+ onScroll // スクロールされるたびに起動する
+ SetValue (name="opacity"....)
+ PlayVideo (synchronously)
+ onStart // 1回起動する
+ onTrackUpdate // 新しいトラックが表示されるたびに起動する
+ SetValue (name="progress"...) // 進捗バーの表示を更新する
+ onStop // 1回起動する
この一連のコマンドは、画面の最上部までスクロールし、項目の1つを読み上げ、ビデオを再生します。再生中にユーザーが画面にタッチすると、実行中の会話、スクロール、ビデオの再生が停止します。
一連のコマンド内の個々のコマンドが、別のシーケンサーを指定することも可能です。そのコマンドに到達すると、適切なシーケンサーに引き渡され、すぐにシーケンス内の次のコマンドが実行されます。sequencerプロパティが明示的に指定されていないコマンドは、現在のシーケンサー上で実行されます。コマンドは、コマンドの遅延が処理された後にのみ、次のシーケンサーで実行されます。たとえば、メインのシーケンサー上で実行される次の一連のコマンドを考えてみましょう。
+ Sequential
+ AnimateItem A (delay=100, duration=1000)
+ AnimateItem B (delay=200, sequencer="other", duration=2000)
+ Parallel (delay=200)
+ AnimateItem C (duration=1000)
+ AnimateItem D (sequencer="other", duration=2000)
+ AnimateItem E (delay=100, duration=1000)
次の表は、このコマンドツリーで発生するタイムラインアクションをまとめたものです。
時間 | アクション |
---|---|
0 | Sequentialコマンドが開始します |
100 | AnimateItem Aが開始します |
1100 | AnimateItem Aが終了します |
1300 | 「other」シーケンサー上でAnimateItem Bが開始します |
1500 | Parallelコマンドが開始します |
AnimateItem Cが開始します | |
「other」シーケンサー上でAnimateItem Dが開始します。AnimateItem Bは終了しています | |
2500 | AnimateItem Cが終了します |
Parallelコマンドが終了します | |
2600 | AnimateItem Eが開始します |
3500 | 「other」シーケンサー上でAnimateItem Dが終了します |
3600 | AnimateItem Eが終了します |
Sequentialが終了します |
コマンドツリーが終了したときは、一定の状態に遷移する必要があります。APLでは次のように想定しています。
- スクロールを停止します。
- ページめくりをキャンセルして、元のページか次のページのどちらか近い方に移動します。
- 会話を直ちに中止します。
- シーンの変更やレイアウトの構造的な変更の場合は、最終的な位置に「ジャンプ」します。