アコーディオンのエフェクト

今日のJavaFXのネタはアコーディオン風のメニューです。ウェブページなどでよく見かける、クリックするとメニューやコンテンツがスーっと表示されるアレです。

アニメーションを使用してノードの高さを調整すれば簡単かなと思いましたが、意外と手こずりました。とはいえ、解ってしまえばソースコードは30行程度・・・。
サンプルはこちらからどうぞ。

ClipView

まずベースを何にしようかと試行錯誤し、CustomNodeやContainerなどを検討したのですが、最終的にClipViewを基底クラスとする事で落ち着きました。
ClipViewは指定した領域でノードの描画領域をコントロールし、さらにマウスのドラッグなどで表示位置を調節できるようなレイアウトです。いわゆるドローソフトやイメージビュワーなどで画像を拡大したときに一部の領域だけ見えてグリグリと動かせるやつです。

ポイントは3点。

まず、アニメーション自体はTimelineを使えば簡単に実装できます。

    public function show() {
        Timeline {
            keyFrames: KeyFrame {
                time: this.duration
                values: clipHeight => node.boundsInParent.height + node.layoutY tween Interpolator.EASEOUT;
            }
        }.play();
        isOpen = true;
    }

高さを次第に大きくしていけばアコーディオンが開くわけです。

次に高さですが、変更時のトリガーをon replace句に設定します。

    var clipHeight:Number = 0 on replace {
        clipY = node.boundsInParent.height + node.layoutY - clipHeight;
        requestLayout();
    };

clipYはClipViewの表示エリアの位置を表します。ここを上手く見せるように計算して設定します。
また、ここが最大のポイントで変更時にrequestLayout関数を呼び出し、レイアウトの調整を依頼することです。これを行わないと下に配置されたノードの位置が上手く再配置されません。

最後のポイントは推奨サイズです。

    override function getPrefWidth(height:Number) { node.boundsInParent.width + node.layoutX; }
    override function getPrefHeight(width:Number) { clipHeight; }

再配置の際には推奨サイズを元にレイアウトが行われます。

以上。