Spark multiline checkbox, multiline radio button and multiline button (with word wrap)
Posted by
Spy 6
This blog post is based on creating a multiline checkbox, but it applies for radio buttons and buttons as well.
In Spark it's as easy as skinning the checkbox. I started off by creating a new MXML Skin and chose the Spark checkbox as the host component. That generated the following code which is actually the default checkbox skin code.
<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" alpha.disabledStates="0.5">
<fx:Metadata>
<![CDATA[
/**
* @copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.CheckBox")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling">
/* Define the skin elements that should not be colorized.
For button, the graphics are colorized but the label is not. */
static private const exclusions:Array = ["labelDisplay", "check"];
/**
* @private
*/
override public function get colorizeExclusions():Array {return exclusions;}
/* Define the symbol fill items that should be colored by the "symbolColor" style. */
static private const symbols:Array = ["checkMarkFill"];
/**
* @private
*/
override public function get symbolItems():Array {return symbols};
/**
* @private
*/
override protected function initializationComplete():void
{
useChromeColor = true;
super.initializationComplete();
}
</fx:Script>
<fx:Script>
<![CDATA[
/**
* @private
*/
private static const focusExclusions:Array = ["labelDisplay"];
/**
* @private
*/
override public function get focusSkinExclusions():Array { return focusExclusions;};
]]>
</fx:Script>
<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:states>
<s:Group verticalCenter="0" width="13" height="13" layoutDirection="ltr">
<!-- drop shadow -->
<s:Rect left="-1" top="-1" right="-1" bottom="-1">
<s:stroke>
<s:LinearGradientStroke rotation="90" weight="1">
<s:GradientEntry color="0x000000"
color.downStates="0xFFFFFF"
alpha="0.011"
alpha.downStates="0" />
<s:GradientEntry color="0x000000"
color.downStates="0xFFFFFF"
alpha="0.121"
alpha.downStates="0.57" />
</s:LinearGradientStroke>
</s:stroke>
</s:Rect>
<!-- fill -->
<s:Rect left="1" top="1" right="1" bottom="1">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF"
color.overStates="0xBBBDBD"
color.downStates="0xAAAAAA"
alpha="0.85" />
<s:GradientEntry color="0xD8D8D8"
color.overStates="0x9FA0A1"
color.downStates="0x929496"
alpha="0.85" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<!-- fill highlight -->
<s:Rect left="1" right="1" top="1" height="5">
<s:fill>
<s:SolidColor color="0xFFFFFF" alpha="0.33" alpha.downStates="0" />
</s:fill>
</s:Rect>
<!-- layer 6: highlight stroke (all states except down) -->
<s:Rect left="1" right="1" top="1" bottom="1" excludeFrom="downStates">
<s:stroke>
<s:LinearGradientStroke rotation="90" weight="1">
<s:GradientEntry color="0xFFFFFF" alpha.overStates="0.33" />
<s:GradientEntry color="0xFFFFFF" alpha="0.12" alpha.overStates="0.0396" />
</s:LinearGradientStroke>
</s:stroke>
</s:Rect>
<!-- layer 6: highlight stroke (down state only) -->
<s:Rect left="1" top="1" bottom="1" width="1" includeIn="downStates">
<s:fill>
<s:SolidColor color="0x000000" alpha="0.07" />
</s:fill>
</s:Rect>
<s:Rect right="1" top="1" bottom="1" width="1" includeIn="downStates">
<s:fill>
<s:SolidColor color="0x000000" alpha="0.07" />
</s:fill>
</s:Rect>
<s:Rect left="1" top="1" right="1" height="1" includeIn="downStates">
<s:fill>
<s:SolidColor color="0x000000" alpha="0.25" />
</s:fill>
</s:Rect>
<s:Rect left="1" top="2" right="1" height="1" includeIn="downStates">
<s:fill>
<s:SolidColor color="0x000000" alpha="0.09" />
</s:fill>
</s:Rect>
<!-- border - put on top of the fill so it doesn't disappear when scale is less than 1 -->
<s:Rect left="0" top="0" right="0" bottom="0">
<s:stroke>
<s:LinearGradientStroke rotation="90" weight="1">
<s:GradientEntry color="0x000000"
alpha="0.5625"
alpha.downStates="0.6375" />
<s:GradientEntry color="0x000000"
alpha="0.75"
alpha.downStates="0.85" />
</s:LinearGradientStroke>
</s:stroke>
</s:Rect>
<!-- checkmark -->
<!--- The checkmark in the box for this skin. To create a custom check mark, create a custom skin class. -->
<s:Path left="2" top="0" includeIn="selectedStates" id="check" itemCreationPolicy="immediate"
data="M 9.2 0.1 L 4.05 6.55 L 3.15 5.0 L 0.05 5.0 L 4.6 9.7 L 12.05 0.1 L 9.2 0.1">
<s:fill>
<!---
@private
The solid color fill for the CheckBox's checkmark. The default alpha is .9, and the default fill color is 0x000000.
-->
<s:SolidColor id="checkMarkFill" color="0" alpha="0.8" />
</s:fill>
</s:Path>
</s:Group>
<!-- Label -->
<!--- @copy spark.components.supportClasses.ButtonBase#labelDisplay -->
<s:Label id="labelDisplay"
textAlign="start"
verticalAlign="middle"
maxDisplayedLines="0"
left="18" right="0" top="3" bottom="3" verticalCenter="2" />
</s:SparkSkin>
1. | <s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" |
2. | xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabledStates="0.5"> |
3. | |
4. | <fx:Metadata> |
5. | <![CDATA[ |
6. | /** |
7. | * @copy spark.skins.spark.ApplicationSkin#hostComponent |
8. | */ |
9. | [HostComponent("spark.components.CheckBox")] |
10. | ]]> |
11. | </fx:Metadata> |
12. | |
13. | <fx:Script fb:purpose="styling"> |
14. | /* Define the skin elements that should not be colorized. |
15. | For button, the graphics are colorized but the label is not. */ |
16. | static private const exclusions:Array = ["labelDisplay", "check"]; |
17. | |
18. | /** |
19. | * @private |
20. | */ |
21. | override public function get colorizeExclusions():Array {return exclusions;} |
22. | |
23. | /* Define the symbol fill items that should be colored by the "symbolColor" style. */ |
24. | static private const symbols:Array = ["checkMarkFill"]; |
25. | |
26. | /** |
27. | * @private |
28. | */ |
29. | override public function get symbolItems():Array {return symbols}; |
30. | |
31. | /** |
32. | * @private |
33. | */ |
34. | override protected function initializationComplete():void |
35. | { |
36. | useChromeColor = true; |
37. | super.initializationComplete(); |
38. | } |
39. | </fx:Script> |
40. | |
41. | <fx:Script> |
42. | <![CDATA[ |
43. | /** |
44. | * @private |
45. | */ |
46. | private static const focusExclusions:Array = ["labelDisplay"]; |
47. | |
48. | /** |
49. | * @private |
50. | */ |
51. | override public function get focusSkinExclusions():Array { return focusExclusions;}; |
52. | ]]> |
53. | </fx:Script> |
54. | |
55. | <s:states> |
56. | <s:State name="up" /> |
57. | <s:State name="over" stateGroups="overStates" /> |
58. | <s:State name="down" stateGroups="downStates" /> |
59. | <s:State name="disabled" stateGroups="disabledStates" /> |
60. | <s:State name="upAndSelected" stateGroups="selectedStates" /> |
61. | <s:State name="overAndSelected" stateGroups="overStates, selectedStates" /> |
62. | <s:State name="downAndSelected" stateGroups="downStates, selectedStates" /> |
63. | <s:State name="disabledAndSelected" stateGroups="disabledStates, selectedStates" /> |
64. | </s:states> |
65. | |
66. | <s:Group verticalCenter="0" width="13" height="13" layoutDirection="ltr"> |
67. | <!-- drop shadow --> |
68. | <s:Rect left="-1" top="-1" right="-1" bottom="-1"> |
69. | <s:stroke> |
70. | <s:LinearGradientStroke rotation="90" weight="1"> |
71. | <s:GradientEntry color="0x000000" |
72. | color.downStates="0xFFFFFF" |
73. | alpha="0.011" |
74. | alpha.downStates="0" /> |
75. | <s:GradientEntry color="0x000000" |
76. | color.downStates="0xFFFFFF" |
77. | alpha="0.121" |
78. | alpha.downStates="0.57" /> |
79. | </s:LinearGradientStroke> |
80. | </s:stroke> |
81. | </s:Rect> |
82. | |
83. | <!-- fill --> |
84. | <s:Rect left="1" top="1" right="1" bottom="1"> |
85. | <s:fill> |
86. | <s:LinearGradient rotation="90"> |
87. | <s:GradientEntry color="0xFFFFFF" |
88. | color.overStates="0xBBBDBD" |
89. | color.downStates="0xAAAAAA" |
90. | alpha="0.85" /> |
91. | <s:GradientEntry color="0xD8D8D8" |
92. | color.overStates="0x9FA0A1" |
93. | color.downStates="0x929496" |
94. | alpha="0.85" /> |
95. | </s:LinearGradient> |
96. | </s:fill> |
97. | </s:Rect> |
98. | |
99. | <!-- fill highlight --> |
100. | <s:Rect left="1" right="1" top="1" height="5"> |
101. | <s:fill> |
102. | <s:SolidColor color="0xFFFFFF" alpha="0.33" alpha.downStates="0" /> |
103. | </s:fill> |
104. | </s:Rect> |
105. | |
106. | <!-- layer 6: highlight stroke (all states except down) --> |
107. | <s:Rect left="1" right="1" top="1" bottom="1" excludeFrom="downStates"> |
108. | <s:stroke> |
109. | <s:LinearGradientStroke rotation="90" weight="1"> |
110. | <s:GradientEntry color="0xFFFFFF" alpha.overStates="0.33" /> |
111. | <s:GradientEntry color="0xFFFFFF" alpha="0.12" alpha.overStates="0.0396" /> |
112. | </s:LinearGradientStroke> |
113. | </s:stroke> |
114. | </s:Rect> |
115. | |
116. | <!-- layer 6: highlight stroke (down state only) --> |
117. | <s:Rect left="1" top="1" bottom="1" width="1" includeIn="downStates"> |
118. | <s:fill> |
119. | <s:SolidColor color="0x000000" alpha="0.07" /> |
120. | </s:fill> |
121. | </s:Rect> |
122. | <s:Rect right="1" top="1" bottom="1" width="1" includeIn="downStates"> |
123. | <s:fill> |
124. | <s:SolidColor color="0x000000" alpha="0.07" /> |
125. | </s:fill> |
126. | </s:Rect> |
127. | <s:Rect left="1" top="1" right="1" height="1" includeIn="downStates"> |
128. | <s:fill> |
129. | <s:SolidColor color="0x000000" alpha="0.25" /> |
130. | </s:fill> |
131. | </s:Rect> |
132. | <s:Rect left="1" top="2" right="1" height="1" includeIn="downStates"> |
133. | <s:fill> |
134. | <s:SolidColor color="0x000000" alpha="0.09" /> |
135. | </s:fill> |
136. | </s:Rect> |
137. | |
138. | <!-- border - put on top of the fill so it doesn't disappear when scale is less than 1 --> |
139. | <s:Rect left="0" top="0" right="0" bottom="0"> |
140. | <s:stroke> |
141. | <s:LinearGradientStroke rotation="90" weight="1"> |
142. | <s:GradientEntry color="0x000000" |
143. | alpha="0.5625" |
144. | alpha.downStates="0.6375" /> |
145. | <s:GradientEntry color="0x000000" |
146. | alpha="0.75" |
147. | alpha.downStates="0.85" /> |
148. | </s:LinearGradientStroke> |
149. | </s:stroke> |
150. | </s:Rect> |
151. | |
152. | <!-- checkmark --> |
153. | <!--- The checkmark in the box for this skin. To create a custom check mark, create a custom skin class. --> |
154. | <s:Path left="2" top="0" includeIn="selectedStates" id="check" itemCreationPolicy="immediate" |
155. | data="M 9.2 0.1 L 4.05 6.55 L 3.15 5.0 L 0.05 5.0 L 4.6 9.7 L 12.05 0.1 L 9.2 0.1"> |
156. | <s:fill> |
157. | <!--- |
158. | @private |
159. | The solid color fill for the CheckBox's checkmark. The default alpha is .9, and the default fill color is 0x000000. |
160. | --> |
161. | <s:SolidColor id="checkMarkFill" color="0" alpha="0.8" /> |
162. | </s:fill> |
163. | </s:Path> |
164. | </s:Group> |
165. | |
166. | <!-- Label --> |
167. | <!--- @copy spark.components.supportClasses.ButtonBase#labelDisplay --> |
168. | <s:Label id="labelDisplay" |
169. | textAlign="start" |
170. | verticalAlign="middle" |
171. | maxDisplayedLines="1" |
172. | left="18" right="0" top="3" bottom="3" verticalCenter="2" /> |
173. | |
174. | </s:SparkSkin> |
175. |
Then I applied this skin to the checkbox instance
<s:CheckBox width="150" height="55" skinClass="CheckSkin"
label="Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... "/>
1. | <s:CheckBox width="150" height="55" skinClass="CheckSkin" |
2. | label="Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... Lorem ipsum et doloret ... "/> |
After you run this the checkbox behaves as before, it displays one line of text, adds ... at the end shows a tooltip with the rest of the text on mouse over. This is all because the maxDisplayedLines property of the Label is set to 1. In this case the checkbox will always show at most 1 line.
Next I played with the maxDisplayedLines property to see what else it can do. Basically if you set a number greater than 1 it will truncate the text to allow at most that number of lines.
maxDisplayedLines=0 Displays as much text as can fit, including even incomplete lines. This doesn't look good, but it might be useful in some cases. It also doesn't show any tooltip.
maxDisplayedLines=0 Displays as much text as can fit, including even incomplete lines. This doesn't look good, but it might be useful in some cases. It also doesn't show any tooltip.
maxDisplayedLines=-1 Displays as much text as can fit, including even incomplete lines. If there is text left out, it adds ... at the end and displays a tooltip with the whole text.
If you remove the height property from the Checkbox, it will autoresize based on the maxDisplayedLines property. If this property is 0 or -1 it will resize to fit all text.
Subscribe to:
Post Comments (Atom)
1 comments:
Hi, nice explanation. Just to know, you can instanziate it via AS:
var cBox:CheckBox = new CheckBox();
cBox.setStyle('skinClass', CheckSkin);
But I got a question for you, is it possible to retrieve the dynamic height of a checkbox (I'm using maxDisplayedLines="-1")?
Post a Comment