Flex 三态复选框

时间:2023-03-09 02:56:25
Flex 三态复选框

在周末挤出了一点时间,写了一个三态复选框的组件,单独使用没有价值,不过集成到树之中可以很好的实现三态树,今天上午便把三态树组件也完成了,Flex自定义组件基本无所不能,此组件基于最新的Flex4.6(也支持Apache Flex4.10,我目前已经全面升级到4.10,为了和以后保持一致),废话不表,呆毛如下:

1.首先创建一个类TriStateCheckBox,继承至CheckBox,为了实现复选框的三种状态,我需要设置三个公开的静态常量来表示,用0,1,2来分别表示Unchecked,Checked和Indeterminate三种状态:

 public class TriStateCheckBox extends CheckBox
{
public static const Unchecked:int = 0;
public static const Checked:int = 1;
public static const Indeterminate:int = 2; public function TriStateCheckBox()
{
super();
}
}

2.为组件自定义一个checkState属性,用来标识复选框的三种状态,这里需要注意的是当状态处于Checked和Indeterminate时,我们认为复选框的selected=true,因此还需要重写复选框的selected属性,实现两者之间的协调统一:

 private var _checkState:int;
[Bindable(event="change")]
[Inspectable(category="General", defaultValue="0")]
public function get checkState():int
{
return _checkState;
}
public function set checkState(value:int):void
{
if(value == _checkState)
return; _checkState = value;
if(_checkState==Indeterminate || _checkState==Checked)
{
_selected = true;
}
else
{
_selected = false;
}
dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));
invalidateSkinState();
} private var _selected:Boolean;
[Bindable]
[Inspectable(category="General", defaultValue="false")]
override public function get selected():Boolean
{
return _selected;
}
override public function set selected(value:Boolean):void
{
if(value == selected && checkState!=Indeterminate)
{
return;
}
_selected = value;
_checkState = _selected?Checked:Unchecked;
dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));
invalidateSkinState();
}

3.现在来考虑复选框的外观,我们新建一个皮肤,主机组件设为上面建立的TriStateCheckBox,然后我们就能看到CheckBox的外观代码,大概分成了两个组,一种是没有勾选的状态:up,over,down,disabled,一种是已勾选状态:upAndSelected,overAndSelected,downAndSelected,disabledAndSelected,用来呈现两种状态,现在我就需要再额外增加一种状态的呈现,所以加入四种状态即可:upAndIndeterminated,overAndIndeterminated,downAndIndeterminated,disabledAndIndeterminated:

 <s:states>
<s:State name="up" />
<s:State name="over" stateGroups="overStates" />
<s:State name="down" stateGroups="downStates" />
<s:State name="disabled" stateGroups="disabledStates" />
<s:State name="upAndSelected" stateGroups="selectedStates" />
<s:State name="overAndSelected" stateGroups="overStates, selectedStates" />
<s:State name="downAndSelected" stateGroups="downStates, selectedStates" />
<s:State name="disabledAndSelected" stateGroups="disabledStates, selectedStates" />
<s:State name="upAndIndeterminated" stateGroups="indeterminatedStates" />
<s:State name="overAndIndeterminated" stateGroups="overStates, indeterminatedStates" />
<s:State name="downAndIndeterminated" stateGroups="downStates, indeterminatedStates" />
<s:State name="disabledAndIndeterminated" stateGroups="disabledStates, indeterminatedStates" />
</s:states>

4.好了,我现在要重写组件的状态切换逻辑,以便使组件根据三种状态来切换对应的state:

 override protected function getCurrentSkinState():String
{
var state:String = super.getCurrentSkinState();
if(checkState==Indeterminate)
{
switch(state)
{
case "up":
case "upAndSelected":
{
state = "upAndIndeterminated";
break;
}
case "over":
case "overAndSelected":
{
state = "overAndIndeterminated";
break;
}
case "down":
case "downAndSelected":
{
state = "downAndIndeterminated";
break;
}
case "disabled":
case "disabledAndSelected":
{
state = "disabledAndIndeterminated";
break;
}
}
}
return state;
}

5.最后,只需要在外观代码中加入我想要的第三种状态的外观即可,我个人还是比较喜欢实心方块的外观,因此我打算直接绘制一个Rect填充,此处是可以自行定义的,比如你喜欢画个空心园来表示第三状态,或者画个灰色的勾,都是可以的,思想没有边界,Flex的强大只有懂的人才能体会:

 <s:Rect left="2" top="2" right="2" bottom="2" includeIn="indeterminatedStates">
<s:fill>
<s:SolidColor id="indeterminatedMarkFill" color="0" alpha="0.8" />
</s:fill>
</s:Rect>