编写超级面板

来源:互联网 发布:java 读取身份证信息 编辑:程序博客网 时间:2024/05/01 18:39
我们需要有如此功能的面板:可以最小化,可以最大化,可以复原,可以拖拽,类似于QQ的停靠功能。
 
解决方案:自定义面板添加相应的功能。
 
难点:在flex4.0当中,怎么在面板头部加上按钮;怎么控制其位置;怎么保存复原信息?做拖拽的时候应该怎么做?
 
 
到了flex4.0,不在有titleBar,不再有chrome函数。adobe提供了另外一种思路,利用皮肤来做。编写皮肤类,在头部加上你想要的按钮。在自定义面板的构造函数当中使用setStyle(“skinClass”)方法引入皮肤。复写partAdded和partRemoved函数,其中利用instance检测实例同时在其中加入事件监听等。值得一说的是需要注意到新的元数据标签SkinPart,有了它可以引入皮肤类里面的组件。
 
面板示例代码如下:

package
{
 import flash.events.MouseEvent;
 import flash.geom.Point;
 import flash.geom.Rectangle;

 import mx.controls.Alert;
 import mx.core.Container;
 import mx.core.IVisualElement;
 import mx.core.UIComponent;
 import mx.effects.Parallel;
 import mx.events.EffectEvent;

 import spark.components.Button;
 import spark.components.Group;
 import spark.components.Panel;
 import spark.effects.Move;
 import spark.effects.Resize;
 import spark.effects.easing.Elastic;
 import spark.effects.easing.IEaser;
 
 //dispatched when max button is click
 [Event(type="MySuperPanelEvent", name="max")]

 //dispatched when titleBar is click
 [Event(type="MySuperPanelEvent", name="min")]

 //dispatched when restore button is click
 [Event(type="MySuperPanelEvent", name="restore")]

 /**
  *
  * @author jixin_huang
  */
 public class MySuperPanel extends Panel
 {
  [SkinPart(required="false")]
  /**
   * 最大化按钮
   * @default
   */
  public var maxBtn:Button;

  [SkinPart(required="false")]
  /**
   *
   * @default
   */
  public var restoreBtn:Button;
  [SkinPart(required="false")]
  /**
   * 标题栏
   * @default
   */
  public var topGroup:Group;
  /**
   *
   * @default
   */
  protected var parallel:Parallel;
  /**
   *
   * @default
   */
  protected var resize:Resize;
  /**
   *
   * @default
   */
  protected var _move:Move;

  /**
   *
   * @default
   */
  protected var restoreRect:Rectangle;

  [Bindable]
  /**
   * 最大化边距
   * @default
   */
  private var _maxGap:Number=5;

  /**
   *
   * @default
   */
  protected var flag:Boolean=false;

  /**
   *
   * @default
   */
  protected var isMinimized:Boolean=false;

  /**
   *
   * @default
   */
  protected var isMaximized:Boolean=false;

  /**
   *
   */
  public function MySuperPanel()
  {
   //TODO: implement function
   super();

   //set defaults

   setStyle("skinClass", MySuperPanelSkin);

   parallel=new Parallel();
   resize=new Resize();
   _move=new Move();
   parallel.addChild(resize);
   parallel.addChild(_move);
  }

  /**
   *
   * @return
   */
  public function get maxGap():Number
  {
   return _maxGap;
  }

  /**
   *
   * @param value
   */
  public function set maxGap(value:Number):void
  {
   _maxGap=value;
  }

  /**
   * 复原
   * @param event
   */
  protected function restoreBtnClickHandler(event:MouseEvent):void
  {

   resize.widthTo=restoreRect.width;
   resize.heightTo=restoreRect.height;

   _move.xTo=restoreRect.x;
   _move.yTo=restoreRect.y;

   parallel.play();

   maxBtn.visible=maxBtn.enabled=true;
   restoreBtn.visible=restoreBtn.enabled=false;

   dispatchEvent(new MySuperPanelEvent("max"));

   isMaximized=false;

   topGroup.addEventListener(MouseEvent.MOUSE_DOWN, topGroupMouseDownHandler);
  }

  /**
   * 最大化
   * @param event
   */
  protected function maxBtnClickHandler(event:MouseEvent):void
  {
   if (!restoreRect)
   {
    restoreRect=new Rectangle(x, y, this.width, this.height);
   }

   parallel.target=this;
   parallel.duration=500;

   resize.widthTo=this.parent.width - 2 * maxGap;
   resize.heightTo=this.parent.height - 2 * maxGap;

   _move.xTo=this.parent.x + maxGap;
   _move.yTo=this.parent.y + maxGap;

   parallel.play();

   maxBtn.visible=maxBtn.enabled=false;
   restoreBtn.visible=restoreBtn.enabled=true;

   Group(this.parent).setElementIndex(this, Group(this.parent).numChildren - 1);

   dispatchEvent(new MySuperPanelEvent("max"));

   isMaximized=true;
   isMinimized=false;

   topGroup.removeEventListener(MouseEvent.MOUSE_DOWN, topGroupMouseDownHandler);
  }

  /**
   *
   * @param event
   */
  protected function topGroupMouseDownHandler(event:MouseEvent):void
  {
   topGroup.addEventListener(MouseEvent.MOUSE_UP, topGroupMouseUpHandler);
   topGroup.addEventListener(MouseEvent.MOUSE_MOVE, topGroupMouseMoveHandler);
  }

  /**
   *
   * @param event
   */
  protected function topGroupMouseUpHandler(event:MouseEvent):void
  {
   topGroup.removeEventListener(MouseEvent.MOUSE_MOVE, topGroupMouseMoveHandler);
   this.stopDrag();

   if (this.y <= 0)
   {
    this.y=-this.height + 4;

    this.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
    this.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
   }
   else
   {
    this.removeEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
    this.removeEventListener(MouseEvent.ROLL_OUT, rollOutHandler);

    /*if (!restoreRect)
    {
     restoreRect=new Rectangle(this.x, this.y, this.width, this.height);
    }
    else
    {
     restoreRect.x=this.x;
     restoreRect.y=this.y;
    }*/
   }
  }

  /**
   *
   * @param event
   */
  protected function topGroupMouseMoveHandler(event:MouseEvent):void
  {
   this.startDrag();
  }

  /**
   *
   * @param event
   */
  protected function rollOverHandler(event:MouseEvent):void
  {
   this.y=-2;
  }

  /**
   *
   * @param event
   */
  protected function rollOutHandler(event:MouseEvent):void
  {
   this.y=-this.height + 4;
  }

  /**
   *
   * @param event
   */

  protected function topGroupDoubleClickHandler(event:MouseEvent):void
  {
   trace(topGroup.height + "");
   if (isMinimized)
   {
    if (restoreRect)
    {
     this.height=restoreRect.height;
    }

    isMinimized=false;
   }
   else if (isMaximized)
   {
    this.height=restoreRect.height;
    this.width=restoreRect.width;
    this.x=restoreRect.x;
    this.y=restoreRect.y;

    isMaximized=false;

    maxBtn.visible=maxBtn.enabled=true;
    restoreBtn.visible=restoreBtn.enabled=false;

    topGroup.addEventListener(MouseEvent.MOUSE_DOWN, topGroupMouseDownHandler);
   }
   else
   {
    if (!restoreRect)
    {
     restoreRect=new Rectangle(this.x, this.y, this.width, this.height);
    }

    this.height=topGroup.height;

    isMinimized=true; //set minimized state;
   }
  }

  /**
   * override functions
   */
  override protected function partAdded(partName:String, instance:Object):void
  {
   super.partAdded(partName, instance);

   if (instance == topGroup)
   {
    topGroup.doubleClickEnabled=true;
    topGroup.addEventListener(MouseEvent.DOUBLE_CLICK, topGroupDoubleClickHandler);

    topGroup.addEventListener(MouseEvent.MOUSE_DOWN, topGroupMouseDownHandler);
   }
   if (instance == maxBtn)
   {
    maxBtn.addEventListener(MouseEvent.CLICK, maxBtnClickHandler);
   }

   if (instance == restoreBtn)
   {
    restoreBtn.addEventListener(MouseEvent.CLICK, restoreBtnClickHandler);
   }

  }

  /**
   *
   * @param partName
   * @param instance
   */
  override protected function partRemoved(partName:String, instance:Object):void
  {
   super.partRemoved(partName, instance);

   if (instance == topGroup)
   {
    topGroup.doubleClickEnabled=false;
    topGroup.removeEventListener(MouseEvent.DOUBLE_CLICK, topGroupDoubleClickHandler);
   }

   if (instance == maxBtn)
   {
    maxBtn.removeEventListener(MouseEvent.CLICK, maxBtnClickHandler);
   }

   if (instance == restoreBtn)
   {
    maxBtn.removeEventListener(MouseEvent.CLICK, restoreBtnClickHandler);
   }
  }
 }
}
 
面板皮肤类的代码如下:

<?xml version="1.0" encoding="utf-8"?>

<!--

  ADOBE SYSTEMS INCORPORATED
  Copyright 2008 Adobe Systems Incorporated
  All Rights Reserved.

  NOTICE: Adobe permits you to use, modify, and distribute this file
  in accordance with the terms of the license agreement accompanying it.

-->

<!--- The default skin class for a Spark Panel container.

  @see spark.components.Panel

  @langversion 3.0
  @playerversion Flash 10
  @playerversion AIR 1.5
  @productversion Flex 4
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
    blendMode="normal"
    mouseEnabled="false"
    minWidth="131"
    minHeight="127"
    alpha.disabled="0.5"
    alpha.disabledWithControlBar="0.5"
    xmlns:mx="library://ns.adobe.com/flex/mx">
 <fx:Metadata>[HostComponent("MySuperPanel")]</fx:Metadata>

 <fx:Script fb:purpose="styling">
  /* Define the skin elements that should not be colorized.
   For panel, border and title background are skinned, but the content area and title text are not. */
  static private const exclusions:Array=["background", "titleDisplay", "contentGroup", "controlBarGroup"];

  /**
   * @private
   */
  override public function get colorizeExclusions():Array
  {
   return exclusions;
  }

  /**
   * @private
   */
  override protected function initializationComplete():void
  {
   useChromeColor=true;
   super.initializationComplete();
  }

  /**
   * @private
   */
  override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
  {
   if (getStyle("borderVisible") == true)
   {
    border.visible=true;
    background.left=background.top=background.right=background.bottom=1;
    contents.left=contents.top=contents.right=contents.bottom=1;
   }
   else
   {
    border.visible=false;
    background.left=background.top=background.right=background.bottom=0;
    contents.left=contents.top=contents.right=contents.bottom=0;
   }

   dropShadow.visible=getStyle("dropShadowVisible");

   var cr:Number=getStyle("cornerRadius");
   var withControls:Boolean=(currentState == "disabledWithControlBar" || currentState == "normalWithControlBar");


   if (cornerRadius != cr)
   {
    cornerRadius=cr;

    dropShadow.tlRadius=cornerRadius;
    dropShadow.trRadius=cornerRadius;
    dropShadow.blRadius=cornerRadius;
    dropShadow.brRadius=cornerRadius;

    setPartCornerRadii(topMaskRect, withControls);
    setPartCornerRadii(border, withControls);
    setPartCornerRadii(background, withControls);
   }

   if (bottomMaskRect)
    setPartCornerRadii(bottomMaskRect, withControls);

   borderStroke.color=getStyle("borderColor");
   borderStroke.alpha=getStyle("borderAlpha");
   backgroundFill.color=getStyle("backgroundColor");
   backgroundFill.alpha=getStyle("backgroundAlpha");

   super.updateDisplayList(unscaledWidth, unscaledHeight);
  }

  /**
   * @private
   */
  private function setPartCornerRadii(target:Rect, includeBottom:Boolean):void
  {
   target.topLeftRadiusX=cornerRadius;
   target.topRightRadiusX=cornerRadius;
   target.bottomLeftRadiusX=cornerRadius;
   target.bottomRightRadiusX=cornerRadius;
  }

  private var cornerRadius:Number;
 </fx:Script>

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

 <!-- drop shadow can't be hittable so it stays sibling of other graphics -->
 <!--- @private -->
 <s:RectangularDropShadow id="dropShadow"
        blurX="20"
        blurY="20"
        alpha="0.32"
        distance="11"
        angle="90"
        color="#000000"
        left="0"
        top="0"
        right="0"
        bottom="0"/>

 <!-- drop shadow can't be hittable so all other graphics go in this group -->
 <s:Group left="0"
    right="0"
    top="0"
    bottom="0">

  <!-- top group mask -->
  <!--- @private -->
  <s:Group left="1"
     top="1"
     right="1"
     bottom="1"
     id="topGroupMask">
   <!--- @private -->
   <s:Rect id="topMaskRect"
     left="0"
     top="0"
     right="0"
     bottom="0">
    <s:fill>
     <s:SolidColor  color="0xdae8eb"/>
    </s:fill>
   </s:Rect>
  </s:Group>

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

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

  <!-- layer 2: background fill -->
  <!--- Defines the appearance of the PanelSkin class's background. -->
  <s:Rect id="background"
    left="1"
    top="1"
    right="1"
    bottom="1">
   <s:fill>
    <!--- @private
      Defines the  PanelSkin class's background fill. The default color is 0xFFFFFF. -->
    <s:SolidColor id="backgroundFill"
         color="#000000"/>
   </s:fill>
  </s:Rect>

  <!-- layer 3: contents -->
  <!--- Contains the vertical stack of titlebar content and controlbar. -->
  <s:Group left="1"
     right="1"
     top="1"
     bottom="1"
     id="contents">
   <s:layout>
    <s:VerticalLayout gap="0"
          horizontalAlign="justify"/>
   </s:layout>

   <!--- @private -->
   <s:Group id="topGroup"
      mask="{topGroupMask}">

    <!-- layer 0: title bar fill -->
    <!--- @private -->
    <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>

    <!-- layer 1: title bar highlight -->
    <!--- @private -->
    <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>

    <!-- layer 2: title bar divider -->
    <!--- @private -->
    <s:Rect id="tbDiv"
      left="0"
      right="0"
      height="1"
      bottom="0">
     <s:fill>
      <s:SolidColor color="0xC0C0C0"/>
     </s:fill>
    </s:Rect>

    <!-- layer 3: text -->
    <!--- @copy spark.components.Panel#titleDisplay -->
    <s:Label id="titleDisplay"
       maxDisplayedLines="1"
       left="9"
       right="3"
       top="1"
       bottom="0"
       minHeight="30"
       verticalAlign="middle"
       fontWeight="bold">
    </s:Label>

    <s:Button id="maxBtn"
        skinClass="MaxBtnSkin"
        verticalCenter="0"
        right="4"/>
    <s:Button id="restoreBtn"
        visible="false"
        enabled="false"
        skinClass="RestoreBtnSkin"
        verticalCenter="0"
        right="4"/>
   </s:Group>

   <!--
     Note: setting the minimum size to 0 here so that changes to the host component's
     size will not be thwarted by this skin part's minimum size.   This is a compromise,
     more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
   -->
   <!--- @copy spark.components.SkinnableContainer#contentGroup -->
   <s:Group id="contentGroup"
      width="100%"
      height="100%"
      minWidth="0"
      minHeight="0">
   </s:Group>

   <!--- @private -->
   <s:Group id="bottomGroup"
      minWidth="0"
      minHeight="0"
      includeIn="normalWithControlBar, disabledWithControlBar">

    <s:Group left="0"
       right="0"
       top="0"
       bottom="0"
       mask="{bottomGroupMask}">

     <!-- layer 0: control bar divider line -->
     <s:Rect left="0"
       right="0"
       top="0"
       height="1"
       alpha="0.22">
      <s:fill>
       <s:SolidColor color="0x000000"/>
      </s:fill>
     </s:Rect>

     <!-- layer 1: control bar highlight -->
     <s:Rect left="0"
       right="0"
       top="1"
       bottom="0">
      <s:stroke>
       <s:LinearGradientStroke rotation="90"
             weight="1">
        <s:GradientEntry color="0xE5E5E5"/>
        <s:GradientEntry color="0xD8D8D8"/>
       </s:LinearGradientStroke>
      </s:stroke>
     </s:Rect>

     <!-- layer 2: control bar fill -->
     <s:Rect left="1"
       right="1"
       top="2"
       bottom="1">
      <s:fill>
       <s:LinearGradient rotation="90">
        <s:GradientEntry color="0xDADADA"/>
        <s:GradientEntry color="0xC5C5C5"/>
       </s:LinearGradient>
      </s:fill>
     </s:Rect>
    </s:Group>
    <!-- layer 3: control bar -->
    <!--- @copy spark.components.Panel#controlBarGroup -->
    <s:Group id="controlBarGroup"
       left="0"
       right="0"
       top="1"
       bottom="1"
       minWidth="0"
       minHeight="0">
     <s:layout>
      <s:HorizontalLayout paddingLeft="10"
           paddingRight="10"
           paddingTop="7"
           paddingBottom="7"
           gap="10"/>
     </s:layout>
    </s:Group>
   </s:Group>
  </s:Group>
 </s:Group>
</s:SparkSkin>
最大化按钮的皮肤类如下:
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:fx="http://ns.adobe.com/mxml/2009">
 <fx:Metadata>[HostComponent("spark.components.Button")]</fx:Metadata>
 <s:states>
  <s:State name="up"/>
  <s:State name="over"/>
  <s:State name="down"/>
  <s:State name="disabled"/>
 </s:states>
 <s:Path data="M 18.5 16.5 C 18.5 17.605 17.605 18.5 16.5 18.5 L 2.5 18.5 C 1.396 18.5 0.5 17.605 0.5 16.5 L 0.5 2.5 C 0.5 1.396 1.396 0.5 2.5 0.5 L 16.5 0.5 C 17.605 0.5 18.5 1.396 18.5 2.5 L 18.5 16.5 Z"
   winding="nonZero"
   x="0"
   y="0">
  <s:stroke.over>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="1"/>
  </s:stroke.over>
  <s:stroke.down>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="1"/>
  </s:stroke.down>
  <s:stroke.disabled>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="1"/>
  </s:stroke.disabled>
  <s:fill>
   <s:SolidColor color="0xffffff"
        alpha="0"
        alpha.over="0.5"/>
  </s:fill>
 </s:Path>
 <s:Rect height="8"
   width="10"
   x="4"
   y="6">
  <s:stroke>
   <s:SolidColorStroke color="0x012012"
        caps="none"
        joints="{JointStyle.ROUND}"
        miterLimit="4"
        weight="1.5"/>
  </s:stroke>
 </s:Rect>
</s:Skin>
复原按钮的皮肤类如下:
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:fx="http://ns.adobe.com/mxml/2009">
 <fx:Metadata>[HostComponent("spark.components.Button")]</fx:Metadata>
 <s:states>
  <s:State name="up"/>
  <s:State name="over"/>
  <s:State name="down"/>
  <s:State name="disabled"/>
 </s:states>
 <s:Path data="M 18.5 16.5 C 18.5 17.605 17.605 18.5 16.5 18.5 L 2.5 18.5 C 1.396 18.5 0.5 17.605 0.5 16.5 L 0.5 2.5 C 0.5 1.396 1.396 0.5 2.5 0.5 L 16.5 0.5 C 17.605 0.5 18.5 1.396 18.5 2.5 L 18.5 16.5 Z"
   winding="nonZero"
   x="0"
   y="0">
  <s:stroke.over>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="1"/>
  </s:stroke.over>
  <s:stroke.down>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="1"/>
  </s:stroke.down>
  <s:stroke.disabled>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="1"/>
  </s:stroke.disabled>
  <s:fill>
   <s:SolidColor color="0xffffff"
        alpha="0"
        alpha.over="0.5"/>
  </s:fill>
 </s:Path>
 <s:Rect height="8"
   width="8"
   x="3"
   y="8">
  <s:stroke>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="2"/>
  </s:stroke>
 </s:Rect>
 <s:Rect height="8"
   width="8"
   x="8"
   y="3">
  <s:stroke>
   <s:SolidColorStroke caps="none"
        joints="miter"
        miterLimit="4"
        weight="2"/>
  </s:stroke>
 </s:Rect>
</s:Skin>
主应用程序代码:

<?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"
      minWidth="955"
      minHeight="600"
      xmlns:local="*">
 <fx:Style>
  @namespace s "library://ns.adobe.com/flex/spark";
  @namespace mx "library://ns.adobe.com/flex/mx";
  @namespace local "*";
  
  
  s|Application{
   background-color:#000000;
  }
 </fx:Style>
 <fx:Declarations>
  <!-- 将非可视元素(例如服务、值对象)放在此处 -->

 </fx:Declarations>
 <!--<local:FxWindow x="55"
   y="195"
   width="330"
   height="250">
   </local:FxWindow>-->
 <local:MySuperPanel title="超级面板"
      x="296"
      y="55"
      width="219"
      height="467"
      cornerRadius="4"
      maxGap="20">
  <local:filters>
   <s:GlowFilter color="0xaebfed"
        blurX="20"
        blurY="20"/>
  </local:filters>
 </local:MySuperPanel>

 
</s:Application>