前回、「徐々にCopy&Pasteコーディングより脱してDRY(Don't repeat yourself)なブロック・コーディングができるよう」と書いたが、反復コードを避ける具体的方法として、MIT App Inventorでは、Any Component Block (generic component)を活用するように薦めている。
通常は、Designer画面で必要なcomponentを配置していくが、もし、36個のImage componentを配置し、それぞれがクリックされた時の動作を設定していくとcomponentの数だけでも相当なものとなる。
個々にテーラーメイド的に作っていくのではなく、generic component(雛形のようなもの)を作り、それをfor each 〜などで必要数設定し、内容も定義していけばcomponentの数も相当減らすことができ、無用なcomponentのcopy & pasteも避けることができるというもの。
「言うは易し行うは難し」の通り、かなり苦戦。今回は、前回の4x4の16マスではなく、6x6の36マスで実験してみた。
確かに、componentの数は減ったし、作成途中でMIT App Inventorが動かなくなったりはしなかったが。。。
実行画面:
スクリーンのデザイン:
動的にcomponentを生成するといっても、どこに生成するかを指示する必要がある。今回は、componentsを横方向配置するHorizonatalArrangementを生成し、各HorizontalArrangementにはImageを6個配置し、そのHorizontalArrangementをさらにVerticalArrangement1の中に縦に6個配置し、計36個のImageを作ることになる。
ブロック・コード:
多分、generic componentの使い方がまだわかっていないので、コード自体が必要以上に複雑になったように思う。ちょっと力任せにやった部分もある。今回、Dynamic Componentsというextensionを使った。要するに、最初から必要数のcomponents (LabelやImage)を作っておくのではなく、データの数などに応じ臨機応変に(Dynamic) componentsを作るためのお助けextension。なお、このextensionの基本的な使い方は、How To Create Dynamic Component using Mit App Inventor 2を参考にした。
当初、Replayボタンが作動しない問題があったが、component IDを全て削除する方法がわかり解決した。これにはかなりの時間を費やした。
また、1と2のランダムなリストを作る際、6個ずつ作成して、それを繋げあわせて36個にしているが、最初から36個のランダムなリストを作るべきと思われる。
1. 1と2がランダムに取得された6個の数字のリストを作成し、変数listに割り当てる。
2. アプリの初期化時に3つの関数を実行。変数allListは、上記makeRandomを関数setComponents内にて6回実行することによりランダムに取得する6x6の36個の1と2のリストを格納するもの。関数の内容は後記。
3. 関数setComponents:全てのcomponentsを生成し、配置する関数。
for each 〜 をネストして、内側のfor each 〜 で横方向に6個のImageをHorizontalArrangementに配置し、外側のfor each ~ で縦方向のVerticalArrangementに6個HorizontalArrangementを配置し、計36個のImageを配置。図式化すると以下。
ちょっとやっかいだったのは、全てのcomponentにIDを付ける必要があったこと。for each 〜 のパラメーターであるnumberとnumを組み合わせて作成。例えば、Imageの1行目は、"1000"+"1" => "10001", "1000"+"2" => "10002" ・・・ "10006"となり、スペース確保用のLabelは、"1000B1"のように間に"B"を挿入した。
上記componentでImageとLabelを生成し、次にプロパティーを設定していくことになる。
Image間にスペースを設けるためのLabelの幅を10pixelsに設定。
また、Imageをclickableにして、幅を50pixelsに設定、上記listの数字に合わせて、1の場合は、fox1.pngを、その他の場合(2)は、owl1.pngの画像を設定。
6個のランダムな1と2のリストを変数allListに追加する。これは外側のfor each 〜 に合わせて6回実行する。このallListはアプリとは直接関係はないが、後で確認のため表示するためのもの。
4. 1と2がそれぞれいくつあるかを格納するlistOneとlistTwoを作成する関数makeOneTwoList
5. 確認用のランダムな36個の1と2のリスト、fox/owl それぞれの画像数(=1と2のそれぞれの個数)をテスト用Labelに表示する関数showProof
6. 従来は、Imageの数だけタップした時の動作を設定していたが、以下の通り、when any Image.Clickのcomponent一つだけになった。(いずれかのImageをタップした時の動作設定)
listOneとlistTwoのitem数を比較し、タップした画像がたくさんいる動物の画像なのかを判別し、その結果をAlertウインドウに表示する。
なお、タップした画像のファイル名を表示するようにした。
7. 関数clearComponents:componentsを配置した時に使ったfor each 〜 ネスト構造をそのまま使ってcomponentのIDを消去した。この方法を思いつくのにかなりの時間を費やした。
8. Replayボタン。上記関数clearComponentsの実行後、変数の初期化、componentsの生成などを再度行う。
今回は、最終的に何とか動くようになったが、まだまだ、知らないことだらけで、MIT App Inventor 道は長く続いているようだ。