自前 Dragger #02

2011.07.20

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

前回に引き続き、自前ドラック機構を用いた Flex の Tips を解説します。

お題「サイズ変更グリッパー」

OS のウィンドウ右下にさりげなく存在するウィンドウサイズ変更のグリッパーボタンですが、Flex の Panel コンポーネントを拡張して、自前で用意してみましょう。

ロジックは、前回のエントリとほぼ同じです。マウスの移動量を基に Panel のサイズを制御しています。

実装コード (ResizablePanel.as)

package jp.classmethod.sample {
import flash.events.MouseEvent;
import spark.components.Button;
import spark.components.Panel;
public class ResizablePanel extends Panel {
    [SkinPart]
    public var gripperButton:Button;
    protected var startMouseX       :int;
    protected var startMouseY       :int;
    protected var startResizeWidth  :Number;
    protected var startResizeHeight :Number;
    public function ResizablePanel() {
        super();
        minWidth  = 200;
        minHeight = 200;
        maxWidth  = 500;
        maxHeight = 500;
        setStyle("skinClass", ResizablePanelSkin);
    }
    protected override function partAdded(partName:String, instance:Object):void {
        super.partAdded(partName, instance);
        if(instance == gripperButton) {
            gripperButton.addEventListener(MouseEvent.MOUSE_DOWN, gripperButtonMouseDownHandler);
        }
    }
    protected function gripperButtonMouseDownHandler(event:MouseEvent):void {
        startMouseX       = mouseX;
        startMouseY       = mouseY;
        startResizeWidth  = width;
        startResizeHeight = height;
        stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler);
        stage.addEventListener(MouseEvent.MOUSE_MOVE, stageMouseMoveHandler);
    }
    protected function stageMouseMoveHandler(event:MouseEvent):void {
        var offsetWidth  :int = mouseX - startMouseX;
        var offsetHeight :int = mouseY - startMouseY;
        var tmpWidth     :int;
        var tmpHeight    :int;
        tmpWidth  = startResizeWidth  + offsetWidth;
        tmpHeight = startResizeHeight + offsetHeight;
        tmpWidth  = tmpWidth  < minWidth  ? minWidth : tmpWidth;
        tmpHeight = tmpHeight < minHeight ? minHeight: tmpHeight;
        width     = tmpWidth  > maxWidth  ? maxWidth  : tmpWidth;
        height    = tmpHeight > maxHeight ? maxHeight : tmpHeight;
        event.updateAfterEvent();
    }
    protected function stageMouseUpHandler(event:MouseEvent):void {
        stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUpHandler);
        stage.removeEventListener(MouseEvent.MOUSE_MOVE, stageMouseMoveHandler);
    }
}
}

実装コード (ResizablePanelSkin.mxml)

<?xml version="1.0" encoding="utf-8"?>
<s:Skin
xmlns:fx                     = "http://ns.adobe.com/mxml/2009"
xmlns:s                      = "library://ns.adobe.com/flex/spark"
mouseEnabled                 = "false"
minWidth                     = "131"
minHeight                    = "127"
alpha.disabled               = "0.5"
alpha.disabledWithControlBar = "0.5"
>

<fx:Metadata>
<![CDATA[
[HostComponent("jp.classmethod.sample.ResizablePanel")]
]]>
</fx:Metadata>

<s:states>
    <s:State name="normal" />
    <s:State name="disabled" />
    <s:State name="normalWithControlBar" stateGroups="withControls" />
    <s:State name="disabledWithControlBar" stateGroups="withControls" />
</s:states>

<s:Group left="0" right="0" top="0" bottom="0">

    <s:Group id="topGroupMask" left="1" top="1" right="1" bottom="1">
        <s:Rect id="topMaskRect" left="0" top="0" right="0" bottom="0">
            <s:fill>
                <s:SolidColor alpha="0" />
            </s:fill>
        </s:Rect>
    </s:Group>

    <s:Group id="bottomGroupMask" left="1" top="1" right="1" bottom="1"
             includeIn="normalWithControlBar, disabledWithControlBar">
        <s:Rect id="bottomMaskRect" left="0" top="0" right="0" bottom="0">
            <s:fill>
                <s:SolidColor alpha="0" />
            </s:fill>
        </s:Rect>
    </s:Group>

    <s:Rect id="border" left="0" right="0" top="0" bottom="0" >
        <s:stroke>
            <s:SolidColorStroke id="borderStroke" weight="1" />
        </s:stroke>
    </s:Rect>

    <s:Rect id="background" left="1" top="1" right="1" bottom="1">
        <s:fill>
            <s:SolidColor id="backgroundFill" color="#FFFFFF" />
        </s:fill>
    </s:Rect>

    <s:Group id="contents" left="1" right="1" top="1" bottom="1">

        <s:layout>
            <s:VerticalLayout gap="0" horizontalAlign="justify" />
        </s:layout>

        <s:Group id="topGroup" mask="{topGroupMask}">

            <s:Rect id="tbFill" left="0" right="0" top="0" bottom="1">
                <s:fill>
                    <s:LinearGradient rotation="90">
                        <s:GradientEntry color="0xE2E2E2" />
                        <s:GradientEntry color="0xD9D9D9" />
                    </s:LinearGradient>
                </s:fill>
            </s:Rect>

            <s:Rect id="tbHilite" left="0" right="0" top="0" bottom="0">
                <s:stroke>
                    <s:LinearGradientStroke rotation="90" weight="1">
                        <s:GradientEntry color="0xEAEAEA" />
                        <s:GradientEntry color="0xD9D9D9" />
                    </s:LinearGradientStroke>
                </s:stroke>
            </s:Rect>

            <s:Rect id="tbDiv" left="0" right="0" height="1" bottom="0">
                <s:fill>
                    <s:SolidColor color="0xC0C0C0" />
                </s:fill>
            </s:Rect>

            <s:Label
                id="titleDisplay" left="9" right="3" top="1" bottom="0" minHeight="30"
                maxDisplayedLines="1" verticalAlign="middle" textAlign="start" fontWeight="bold" />

        </s:Group>

        <s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0" />

    </s:Group>

    <s:Button
        id="gripperButton"
        width="30" height="30" right="0" bottom="0"
        buttonMode="true" chromeColor="0x990000" />

</s:Group>

</s:Skin>

実装コード (Main.mxml)

<?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:cm        = "jp.classmethod.sample.*"
backgroundAlpha = "1"
backgroundColor = "0x333333"
>

<cm:ResizablePanel width="200" height="300" verticalCenter="0" horizontalCenter="0">
    <cm:layout>
        <s:VerticalLayout paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="40" />
    </cm:layout>
    <s:Button width="100%" height="100%" />
    <s:Button width="100%" height="100%" />
    <s:Button width="100%" height="100%" />
    <s:Button width="100%" height="100%" />
</cm:ResizablePanel>

</s:Application>

出力結果

出力結果は次の通り

[SWF]http://publick-blog.s3.amazonaws.com/wp-content/uploads/2011/07/DragLesson02.swf,640,480[/SWF]

次回は、もう少し応用を効かせたものを紹介します。