在周末擠出了一點時間,寫了一個三態復選框的組件,單獨使用沒有價值,不過集成到樹之中可以很好的實現三態樹,今天上午便把三態樹組件也完成了,Flex自定義組件基本無所不能,此組件基於最新的Flex4.6(也支持Apache Flex4.10,我目前已經全面升級到4.10,為了和以后保持一致),廢話不表,呆毛如下:
1.首先創建一個類TriStateCheckBox,繼承至CheckBox,為了實現復選框的三種狀態,我需要設置三個公開的靜態常量來表示,用0,1,2來分別表示Unchecked,Checked和Indeterminate三種狀態:
1 public class TriStateCheckBox extends CheckBox 2 { 3 public static const Unchecked:int = 0; 4 public static const Checked:int = 1; 5 public static const Indeterminate:int = 2; 6 7 public function TriStateCheckBox() 8 { 9 super(); 10 } 11 }
2.為組件自定義一個checkState屬性,用來標識復選框的三種狀態,這里需要注意的是當狀態處於Checked和Indeterminate時,我們認為復選框的selected=true,因此還需要重寫復選框的selected屬性,實現兩者之間的協調統一:
1 private var _checkState:int; 2 [Bindable(event="change")] 3 [Inspectable(category="General", defaultValue="0")] 4 public function get checkState():int 5 { 6 return _checkState; 7 } 8 public function set checkState(value:int):void 9 { 10 if(value == _checkState) 11 return; 12 13 _checkState = value; 14 if(_checkState==Indeterminate || _checkState==Checked) 15 { 16 _selected = true; 17 } 18 else 19 { 20 _selected = false; 21 } 22 dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT)); 23 invalidateSkinState(); 24 } 25 26 private var _selected:Boolean; 27 [Bindable] 28 [Inspectable(category="General", defaultValue="false")] 29 override public function get selected():Boolean 30 { 31 return _selected; 32 } 33 override public function set selected(value:Boolean):void 34 { 35 if(value == selected && checkState!=Indeterminate) 36 { 37 return; 38 } 39 _selected = value; 40 _checkState = _selected?Checked:Unchecked; 41 dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT)); 42 invalidateSkinState(); 43 }
3.現在來考慮復選框的外觀,我們新建一個皮膚,主機組件設為上面建立的TriStateCheckBox,然后我們就能看到CheckBox的外觀代碼,大概分成了兩個組,一種是沒有勾選的狀態:up,over,down,disabled,一種是已勾選狀態:upAndSelected,overAndSelected,downAndSelected,disabledAndSelected,用來呈現兩種狀態,現在我就需要再額外增加一種狀態的呈現,所以加入四種狀態即可:upAndIndeterminated,overAndIndeterminated,downAndIndeterminated,disabledAndIndeterminated:
1 <s:states> 2 <s:State name="up" /> 3 <s:State name="over" stateGroups="overStates" /> 4 <s:State name="down" stateGroups="downStates" /> 5 <s:State name="disabled" stateGroups="disabledStates" /> 6 <s:State name="upAndSelected" stateGroups="selectedStates" /> 7 <s:State name="overAndSelected" stateGroups="overStates, selectedStates" /> 8 <s:State name="downAndSelected" stateGroups="downStates, selectedStates" /> 9 <s:State name="disabledAndSelected" stateGroups="disabledStates, selectedStates" /> 10 <s:State name="upAndIndeterminated" stateGroups="indeterminatedStates" /> 11 <s:State name="overAndIndeterminated" stateGroups="overStates, indeterminatedStates" /> 12 <s:State name="downAndIndeterminated" stateGroups="downStates, indeterminatedStates" /> 13 <s:State name="disabledAndIndeterminated" stateGroups="disabledStates, indeterminatedStates" /> 14 </s:states>
4.好了,我現在要重寫組件的狀態切換邏輯,以便使組件根據三種狀態來切換對應的state:
1 override protected function getCurrentSkinState():String 2 { 3 var state:String = super.getCurrentSkinState(); 4 if(checkState==Indeterminate) 5 { 6 switch(state) 7 { 8 case "up": 9 case "upAndSelected": 10 { 11 state = "upAndIndeterminated"; 12 break; 13 } 14 case "over": 15 case "overAndSelected": 16 { 17 state = "overAndIndeterminated"; 18 break; 19 } 20 case "down": 21 case "downAndSelected": 22 { 23 state = "downAndIndeterminated"; 24 break; 25 } 26 case "disabled": 27 case "disabledAndSelected": 28 { 29 state = "disabledAndIndeterminated"; 30 break; 31 } 32 } 33 } 34 return state; 35 }
5.最后,只需要在外觀代碼中加入我想要的第三種狀態的外觀即可,我個人還是比較喜歡實心方塊的外觀,因此我打算直接繪制一個Rect填充,此處是可以自行定義的,比如你喜歡畫個空心園來表示第三狀態,或者畫個灰色的勾,都是可以的,思想沒有邊界,Flex的強大只有懂的人才能體會:
1 <s:Rect left="2" top="2" right="2" bottom="2" includeIn="indeterminatedStates"> 2 <s:fill> 3 <s:SolidColor id="indeterminatedMarkFill" color="0" alpha="0.8" /> 4 </s:fill> 5 </s:Rect>