謎の矩形「whiteBox」を除去する

2011.07.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

毎度お世話になっております。クラスメソッドの稲毛です。

今回は、Flex開発の中で得たTipsを紹介したいと思います。

「whiteBox」とは?

「whiteBox」とは、スクロールバーが表示されているコンテナの右下角に表示される矩形領域の事を指します。

次のサンプルを御覧ください。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                layout="absolute"
                backgroundColor="#4169e1">
    <mx:Box width="640"
            height="480"
            backgroundColor="#4169e1"/>
</mx:Application>

[SWF]http://publick-blog.s3.amazonaws.com/wp-content/uploads/2011/07/whiteBox_mx_sample_1.swf, 320, 240[/SWF]

縦スクロールバーの下端と横スクロールバーの右端で囲まれた白い領域、これが「whiteBox」です。実はこの領域の「白色」は、その名が示すとおり「#FFFFFFの塗り」がハードコーディングされています。

次に「mx.core.Container」クラスのソースから当該部分を引用します。

        if (horizontalScrollBar && verticalScrollBar)
        {
            if (!whiteBox)
            {
                whiteBox = new FlexShape();
                whiteBox.name = "whiteBox";

                var g:Graphics = whiteBox.graphics;
                g.beginFill(0xFFFFFF);
                g.drawRect(0, 0, verticalScrollBar.minWidth, horizontalScrollBar.minHeight);
                g.endFill()

                rawChildren.addChild(whiteBox);
            }
        }
        else
        {
            if (whiteBox)
            {
                rawChildren.removeChild(whiteBox);
                whiteBox = null;
            }
        }

4591行目で「0xFFFFFF」が塗りの色として指定されていますね。この為、「この領域を透過させて背景色と合わせたい!」といった時に「スタイルの指定で手軽に!」とはいかないのです。

「whiteBox」を除去する

それではこの領域は永遠に「whiteBox」なのでしょうか?実は除去(クリア)する方法がADCクックブックに掲載されています。

描画更新時に除去する方法

次のリンク先をご参照ください。 Remove white box at bottom right corner of containers when scroll bars are visible

この記事では、描画更新毎に「rawChildren」から「whiteBox」を探し出して描画をクリアする方法を紹介しています。この方法は、公開されているメソッドのオーバーライドだけで実現できる単純明快なものとなっていますが、描画更新時に毎回クリア処理が実行されるので、描画への影響を少しでも抑えたい場合の為に以下のような方法を試してみました。

「whiteBox」生成時に除去する方法

「whiteBox」は表示される際に生成および描画が行われ、非表示となる際にそのインスタンス(mx.core.FlexShape)が「rawChildren」から破棄されます。この「表示」の際に「rawChildren.addChild()」メソッドによって描画オブジェクトとしての追加が行われるのですが、このメソッドの実体は「mx.core.mx_internal」名前空間でコンテナクラス自身に「rawChildren_addChild()」メソッドとして実装されています。このメソッドをオーバーライドして、追加対象が「whiteBox」の時にクリアする処理としたものが以下のサンプルとなります。

package
{
import flash.display.DisplayObject;

import mx.core.Application;
import mx.core.FlexShape;
import mx.core.mx_internal;

use namespace mx_internal;

public class CustomApplication extends Application
{
    public function CustomApplication()
    {
        super();
    }
    
    override mx_internal function rawChildren_addChild(child:DisplayObject):DisplayObject
    {
        if (child.name == "whiteBox")
            FlexShape(child).graphics.clear();
        return super.rawChildren_addChild(child);
    }
}
}
<?xml version="1.0" encoding="utf-8"?>
<CustomApplication xmlns:mx="http://www.adobe.com/2006/mxml"
                   xmlns="*"
                   layout="absolute"
                   backgroundColor="#4169e1">
    <mx:Box width="640"
            height="480"
            backgroundColor="#4169e1"/>
</CustomApplication>

[SWF]http://publick-blog.s3.amazonaws.com/wp-content/uploads/2011/07/whiteBox_mx_sample_2.swf, 320, 240[/SWF]

問題なく「whiteBox」がクリアされていますね。この方法では「whiteBox」生成時にのみクリア処理が実行されますが、「mx.core.mx_internal」名前空間で定義されているFlex Frameworkの内部構造へアクセスしていますので、くれぐれも取り扱いにはご注意ください。

Sparkコンポーネントでは?

なお、Flex 4系のSparkコンポーネントでは、スクロールバー表示時に「whiteBox」は表示されません。構造の大幅刷新で「whiteBox」は取り除かれてしまったようですね。

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx"
               backgroundColor="#4169e1">
    <s:Scroller width="100%"
                height="100%">
        <s:Group>
            <s:BorderContainer width="640"
                               height="480"
                               backgroundColor="#4169e1"/>
        </s:Group>
    </s:Scroller>
</s:Application>

[SWF]http://publick-blog.s3.amazonaws.com/wp-content/uploads/2011/07/whiteBox_spark_sample.swf, 320, 240[/SWF]

ソースコードの表示を修正しました。