ListUI for as3を作った。

FLASHer その2 Advent Calendar 2016の20日目の記事です。

github.com

どんなライブラリなの!

 タッチでスクロールが出来てドラッグで並べ替えが出来る気持ちの良いListUIライブラリです。リストのセルや右側に出るスクロールバー等、すべてが拡張(自作)することを想定して作られているため、使用のハードルがやや高いかもしれません。デフォルトスキンなどが存在しません。作ってください!
 最近は特にflashはオワコン!とか言われてはいますが、AIR等を使ったアプリやソフト。そういったものは意外と世の中で生きています。(展示物系等でも多いです。)そういった部分で必要になったので作りました。
 as3がある程度分かる人に向けた解説になります。分かる人はgithubのサンプルのソース読んでください笑。

サンプルを用いて解説

サンプルを用意しました。
サンプルの機能:
・セルをタッチすると、そのデータがログに出る。
・右の方をドラッグで並べ替え。
・左の方クリックで削除。
・ドラッグや削除でデータに変更があるとログに出る。

f:id:takumus:20161219182319p:plain

demo : http://takumus.com/labs/list-ui-for-as3/samples/demo/
demoのソース : github.com

Listクラス

demoのメインクラスである、Demo.asから重要な部分を切り出しました。
gist.github.com  Listクラスは、初期化時にセルクラス、セルの高さ、セル同士の間隔、スクロールバークラスを要求します。 必須なのはセルクラス、セルの高さだけです。セルクラスについての説明は下で行います。
 Listにデータをセットするにはlist.setDataを呼びます。Arrayを渡すだけです。demoでは、A~Uまでを渡しています。
 セルから送られてくるメッセージを受け取るには、ListEvent.MESSAGEを追加します。メッセージについても下で解説します。
 Listのデータに変更があった場合、ListEvent.UPDATEが発火されます。この時、変更後のデータはlist.getData()で取得できます。

ListCellクラス

 demoのSimpleCell.asを見てみましょう。これはDemoのセルクラスです。削除ボタンや、ソートボタン、そしてラベルなどが配置されているのが分かります。List初期化時に渡していたセルクラスとはこれの事です。ListCellを継承して作ったオリジナルのセルです。このように渡すことで、Listはこれを生成し画面に配置してくれます。

resizeメソッド

 ListCellにはresizeというメソッドがあります。これはCellがレスポンシブであるために用意されたもので、Listのresize時に呼ばれます。SimpleCellでもresizeをオーバーライドして、テキストやボタンの位置、背景の再描画を行っています。基本的にはresizeはオーバーライドしてください。

setDataメソッド

 ListCellにはsetDataというメソッドがあります。これはセルのデータが更新された時に呼ばれます。今回、ListにsetData("ABCDEFGH...".split(""))という具合でStringの配列を渡したので、setData(data:CellData)のdata.dataはStringになります。(ジェネリクス使った方が良かったですね。今度直します。)
 例えば今回のSimpleCell.asで、setDataメソッドは
_label.text = data.data.toString();
と実装されています。dataはCellDataなのでdata.dataとしなければいけない事に注意してください。

クリック、タッチ、そしてmessage、remove、sort...

 細かい解説の前に、注意点があります。タッチイベント、マウスイベントはどちらも必ずListCellMouseEventを使います。bodyに対して通常のマウスイベントやタッチイベントを追加してはいけません
 その理由として、例えばスクロールのためにセルをドラッグしてリリースする過程で、通常のイベントは、タッチもしくはクリックを発行します。スクロールしたときはイベントが出ないようにしたり、その他おかしな挙動が起こらないようなListCellMouseEventを定義してあります。なのでこちらを使いましょう。  SimpleCell.asに、このような記述があります。これはCellがマウスや指によって押された時の処理です。 gist.github.com  まずListCellMouseEvent.MOUSE_DOWN時に、マウスが右の方(ドラッグアイコンの位置)だったら、beginSort()を呼んでいます。これはListCellのメソッドで、as3で言うstartDrag()のようなもので、ドラッグアンドドロップによるソートを開始するというものです。マウスやタッチが解除され次第、勝手に終了するので、ソートを開始させたいボタン等がListCellMouseEvent.MOUSE_DOWNされた時にbeginSort()を呼べばdemoのような挙動をします。ソート完了時、ListEvent.UPDATEを発火します。
 次に、ListCellMouseEvent.CLICK時に、マウスが左の方(削除アイコンの位置)だったらremove()が呼ばれています。これもListCellのメソッドで、このセルを削除するという命令を出すものになっています。これが呼ばれた瞬間削除されます。削除確認ボタンを点けたい場合は、自前で実装してください。※削除完了時に、ListEvent.REMOVEを発火します。
 また、マウスがセル自体をクリックした場合にmessage()が呼ばれています。これは、ListCellからListへメッセージを渡すことが出来るListCellのメソッドです。引数に何らかのデータを入れることも出来ます。
 今回、message("Hi. My data is [" + data.data + "]")となっていますので、demoではセルタッチ時にログにこのようなメッセージが出ると思います。これは、Listクラスのインスタンスに対し、ListEvent.MESSAGEでハンドル出来ます。Demo.asを見ていただければ分かると思います。

スクロールバーのカスタマイズ

 正確にはバー自体をドラッグでスクロールする事はできないので、ただのスクロール(する位置を示す)バーですが!
 これについては、SimpleScrollBar.asを見ていただきたいと思います。
 resize時にレンダリングするようにresizeをオーバーライドするだけで完了です。new List()するときに4番目にそのインスタンスを渡せばよいです。

ListCellのインスタンス生成数とデータ数の関係について(割と重要)

 今回のUIは、ListCellのインスタンス数を極力減らすように心がけています。画面内に収まる最低の個数だけ生成し、データ数が1万件あろうが画面に5セルしか表示できないのであれば5つのインスタンスしか生成しません。
 これにより、パフォーマンスの向上を実現しています。一つのセルインスタンスとデータは対になっている訳ではないので、設計時は注意が必要です。setDataが全てです。

謝罪

 ライブラリの開発経験も浅く、自分のライブラリの説明などしたことが無いので随分とごちゃごちゃしてしまいました。それでも使用してくださる方がおりましたら、長い時間をかけてサンプルを見て解読していただくか、私に連絡していただけると幸いです! → me(あっ)takumus.com