Flex 4 でオサレなアルファマスク List コンポーネント

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

Flex 4 コンポーネント拡張の小ネタを紹介します。

アルファマスクは、ブレンドモードを使用することによって実現できます。 マスク対象コンポーネントとマスクの関係を「表示オブジェクトの親子関係」として、マスク対象コンポーネントのブレンドモードを「レイヤー (BlendMode.LAYER) 」、マスクのブレンドモードを「削除 (BlendMode.ERASE) 」と定義することによって、「塗りのアルファ」がマスクとして機能します。

実装コード (AlphaMaskList.as)

package jp.classmethod.sample {
    import flash.display.BlendMode;
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.geom.Matrix;
    import spark.components.List;
    import spark.core.SpriteVisualElement;
    /** <p>maskColors 配列内の各色に対応するアルファ値の配列。有効な値は 0 ~ 1 です。 0 未満の値を指定した場合、デフォルトで 0 が適用されます。1 より大きい値を指定した場合、デフォルトで 1 が適用されます。</p> */
    [Style(name="maskAlphas", type="Array", arrayType="int", inherit="no")]
    /** <p>グラデーションで使用する RGB 16 進カラー値の配列 ( 赤 0xFF0000、青 0x0000FF など )。 最大 15 色まで指定できます。 各色について、maskAlphas スタイルプロパティと  maskRatios スタイルプロパティに対応する値を指定してください。 </p> */
    [Style(name="maskColors", type="Array", arrayType="int", inherit="no")]
    /** <p>色分布比率の配列です。0 ~ 255 の範囲の値を指定できます。この値は、100% でサンプリングされる色の幅の割合をパーセントで定義します。 値 0 はグラデーションボックスの左の位置を表し、255 はグラデーションボックスの右の位置を表します。</p>  */
    [Style(name="maskRatios", type="Array", arrayType="int", inherit="no")]
    /**
     * <p>オサレなアルファマスク List コンポーネント</p>
     * @author taiga
     */
    public class AlphaMaskList extends List {
        /** <p>mask alphas</p> */
        protected var _maskAlphas:Array;
        /** <p>mask colors</p> */
        protected var _maskColors:Array;
        /** <p>mask ratios</p> */
        protected var _maskRatios:Array;
        [SkinPart]
        /** <p>アルファマスク</p> */
        public var alphaMask:SpriteVisualElement;
        /** <p>コンストラクタ</p> */
        public function AlphaMaskList() {
            super();
            setStyle("skinClass", AlphaMaskListSkin);
            blendMode   = BlendMode.LAYER;
            _maskColors = [0, 0, 0];
            _maskAlphas = [1, 0, 1];
            _maskRatios = [0, 127, 255];
        }
        /** @private */
        protected override function partAdded(partName:String, instance:Object):void {
            super.partAdded(partName, instance);
            if(instance == alphaMask) {
                alphaMask.includeInLayout = false;
                alphaMask.mouseEnabled = false;
                alphaMask.blendMode = BlendMode.ERASE;
            }
        }
        /** @private */
        protected override function commitProperties():void {
            super.commitProperties();
            var alphas:Array = getStyle("maskAlphas");
            var colors:Array = getStyle("maskColors");
            var ratios:Array = getStyle("maskRatios");
            if(alphas != null) {
                _maskAlphas = alphas;
            }
            if(colors != null) {
                _maskColors = colors;
            }
            if(ratios != null) {
                _maskRatios = ratios;
            }
        }
        /** @private */
        protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
            if(alphaMask != null) {
                var g   : Graphics;
                var m   : Matrix;
                var rad : Number;
                var w   : Number;
                var h   : Number;
                rad = Math.PI * 0.5;
                w = unscaledWidth - 16;
                h = unscaledHeight - 2;
                m = new Matrix();
                m.createGradientBox(w, h, rad);
                g = alphaMask.graphics;
                g.clear();
                g.beginGradientFill(GradientType.LINEAR, _maskColors, _maskAlphas, _maskRatios, m);
                g.drawRect(1, 1, w, h);
                g.endFill();
            }
        }
    }
}

実装コード (AlphaMaskListSkin.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"
minWidth       = "112"
alpha.disabled = "0.5"
blendMode      = "normal"
>

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

<s:states>
    <s:State name="normal" />
    <s:State name="disabled" />
</s:states>

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

<s:Rect id="background" left="1" right="1" top="1" bottom="1" >
    <s:fill>
        <s:SolidColor id="bgFill" color="0xFFFFFF" />
    </s:fill>
</s:Rect>

<s:Scroller left="0" top="0" right="0" bottom="0" id="scroller" minViewportInset="1" hasFocusableChildren="false">
    <s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
        <s:layout>
            <s:VerticalLayout gap="0" horizontalAlign="contentJustify" requestedMinRowCount="5" paddingTop="100" paddingBottom="100" />
        </s:layout>
    </s:DataGroup>
</s:Scroller>

<s:SpriteVisualElement id="alphaMask" left="0" top="0" right="0" bottom="0" />

</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.*"
fontSize = "30"
>

<cm:AlphaMaskList
width            = "300"
height           = "400"
verticalCenter   = "0"
horizontalCenter = "0"
itemRenderer     = "spark.skins.spark.DefaultComplexItemRenderer"
>
    <cm:dataProvider>
        <s:ArrayList>
            <s:Button label="AAAA" width="100%" height="50" />
            <s:Button label="BBBB" width="100%" height="50" />
            <s:Button label="CCCC" width="100%" height="50" />
            <s:Button label="DDDD" width="100%" height="50" />
            <s:Button label="EEEE" width="100%" height="50" />
            <s:Button label="FFFF" width="100%" height="50" />
            <s:Button label="GGGG" width="100%" height="50" />
            <s:Button label="HHHH" width="100%" height="50" />
            <s:Button label="IIII" width="100%" height="50" />
            <s:Button label="JJJJ" width="100%" height="50" />
            <s:Button label="KKKK" width="100%" height="50" />
            <s:Button label="LLLL" width="100%" height="50" />
            <s:Button label="MMMM" width="100%" height="50" />
            <s:Button label="NNNN" width="100%" height="50" />
        </s:ArrayList>
    </cm:dataProvider>
</cm:AlphaMaskList>

</s:Application>

出力結果

出力結果は次の通り

This movie requires Flash Player 9