I'm trying to use an image (embedded) for the thumb on my Spark slider component. This should be straightforward -- I know what to do in mx -- but I haven't been able to find what the Spark syntax is.
I don't even need states (up, down, over, etc) since this is going on a mobile app.
Does anyone know?
Thanks.
Your Spark Slider requires a custom skin class, and that skin requires a SliderThumbSkin for the thumb.
Spark Slider:
<?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">
<s:VSlider skinClass="SliderSkin" />
</s:Application>
SliderSkin - Spark Slider's skin class requires a thumb skin:
<!--- The default skin class is VSliderThumbSkin.
#copy spark.components.supportClasses.TrackBase#thumb
#see spark.skins.spark.VSliderThumbSkin -->
<s:Button id="thumb" left="0" right="0" width="11" height="11"
tabEnabled="false"
skinClass="SliderThumbSkin" />
This is the only change to the VSliderSkin. If you need the entire skin code, it is below in the Additional Information section of this answer.
SliderThumbSkin - Thumb skin's button thumb requires skin for images:
<?xml version="1.0" encoding="utf-8"?>
<s:SparkButtonSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
minWidth="21"
minHeight="21"
alpha.disabled="0.5">
<fx:Metadata>
<![CDATA[
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.Button")]
]]>
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<s:Image source.up="https://www.google.com/intl/en_com/images/srpr/logo3w.png"
source.over="https://www.google.com/intl/en_com/images/srpr/logo3w.png"
source.down="https://www.google.com/intl/en_com/images/srpr/logo3w.png"
source.disabled="https://www.google.com/intl/en_com/images/srpr/logo3w.png"
width="20"
height="20" />
</s:SparkButtonSkin>
Here, I've replaced the thumb with the Google logo:
Additional Information
These skins can be auto-generated using Flash Builder's content assist by [CTRL/COMMAND+SPACE] inside the quotes of skinClass="" appearing as such:
This will bring up a dialog to create a new MXML skin:
Default skins are in the SDK by theme. For Spark it'd be something like:
C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.5\sdks\4.5.1\frameworks\projects\spark\src\spark\skins\spark
Here is the entire SliderSkin class
<?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 the Spark VSlider component. The thumb and track skins are defined by the
VSliderThumbSkin and VSliderTrackSkin classes, respectively.
#see spark.components.VSlider
#see spark.skins.spark.VSliderThumbSkin
#see spark.skins.spark.VSliderTrackSkin
#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" minWidth="11" alpha.disabled="0.5">
<fx:Metadata>
<![CDATA[
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.VSlider")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling">
/* Define the skin elements that should not be colorized.
For slider, the skin itself is colorized but the individual parts are not. */
static private const exclusions:Array = ["track", "thumb"];
/**
* #private
*/
override public function get colorizeExclusions():Array {return exclusions;}
/**
* #private
*/
override protected function initializationComplete():void
{
useChromeColor = true;
super.initializationComplete();
}
</fx:Script>
<fx:Script>
/**
* #private
*/
override protected function measure() : void
{
// Temporarily move the thumb to the top of the Slider so measurement
// doesn't factor in its y position. This allows resizing the
// VSlider to less than 100px in height.
var thumbPos:Number = thumb.getLayoutBoundsY();
thumb.setLayoutBoundsPosition(thumb.getLayoutBoundsX(), 0);
super.measure();
thumb.setLayoutBoundsPosition(thumb.getLayoutBoundsX(), thumbPos);
}
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<fx:Declarations>
<!--- The tooltip used in the mx.controls.Slider control.
To customize the DataTip's appearance, create a custom VSliderSkin class. -->
<fx:Component id="dataTip">
<s:DataRenderer minHeight="24" minWidth="40" x="20">
<s:Rect top="0" left="0" right="0" bottom="0">
<s:fill>
<s:SolidColor color="0x000000" alpha=".9"/>
</s:fill>
<s:filters>
<s:DropShadowFilter angle="90" color="0x999999" distance="3"/>
</s:filters>
</s:Rect>
<s:Label id="labelDisplay" text="{data}"
horizontalCenter="0" verticalCenter="1"
left="5" right="5" top="5" bottom="5"
textAlign="center" verticalAlign="middle"
fontWeight="normal" color="white" fontSize="11">
</s:Label>
</s:DataRenderer>
</fx:Component>
</fx:Declarations>
<!--- The default skin class is VSliderTrackSkin.
#copy spark.components.supportClasses.TrackBase#track
#see spark.skins.spark.VSliderTrackSkin -->
<s:Button id="track" left="0" right="0" top="0" bottom="0" minHeight="33" height="100"
tabEnabled="false"
skinClass="spark.skins.spark.VSliderTrackSkin" />
<!--- The default skin class is VSliderThumbSkin.
#copy spark.components.supportClasses.TrackBase#thumb
#see spark.skins.spark.VSliderThumbSkin -->
<s:Button id="thumb" left="0" right="0" width="11" height="11"
tabEnabled="false"
skinClass="SliderThumbSkin" />
</s:SparkSkin>
Related
(another of my never ending questions...)
I need an image component with states which behaves like a ToggleButton. Rather than build from scratch I thought I would try subclassing ToggleButton and defining a custom Flex skin. I don't have much experience with skinning and have cobbled together the code below.
It seems to work well – binding BitmapImages in the skin to BitmapData loading in the button instance: <s:BitmapImage source="{hostComponent.upImageData}"
Am I on the right track with this approach? Is there a more standard approach to this sort of thing?
ToggleButton Skin
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
minWidth="21" minHeight="21"
alpha.disabledStates="0.5">
<fx:Metadata>[HostComponent("components.EventButton")]</fx:Metadata>
<!-- host component -->
<!-- states -->
<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, selectedUpStates" />
<s:State name="overAndSelected" stateGroups="overStates, selectedStates" />
<s:State name="downAndSelected" stateGroups="downStates, selectedStates" />
<s:State name="disabledAndSelected" stateGroups="selectedUpStates, disabledStates, selectedStates" />
</s:states>
<s:BitmapImage source="{hostComponent.upImageData}"
includeIn="up, disabled"
left="0" right="0" top="0" bottom="0" />
<s:BitmapImage source="{hostComponent.overImageData}"
left="0" right="0" top="0" bottom="0"
includeIn="over"/>
<s:BitmapImage source="{hostComponent.downImageData}"
left="0" right="0" top="0" bottom="0"
includeIn="down, upAndSelected, overAndSelected, downAndSelected"/>
</s:Skin>
ToggleButton
<?xml version="1.0" encoding="utf-8"?>
<s:ToggleButton xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:skins = "skins.*"
skinClass="skins.EventSkin"
creationComplete="creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
[Bindable]
public var upImageData:BitmapData;
[Bindable]
public var overImageData:BitmapData;
[Bindable]
public var downImageData:BitmapData;
[Bindable]
public var disabledImageData:BitmapData;
// image loading code removed
]]>
</fx:Script>
</s:ToggleButton>
Yep, you are going in right way. The "Skin mechanism" is really powerful and flexible tool. I had similar task about year ago and I solved it in the same way (just with standard ToggleButton and custom skin). All changes in visual representation of spark component might to be in skin class.
As another option, you should be able to use the state variable syntax:
<s:ToggleButton icon.up="{upIcon}"
icon.over="{overIcon}"
icon.down="{downIcon}"
icon.disabled="{disabledIcon}"
icon.upAndSelected="{upAndSelectedIcon}"
icon.overAndSelected="{overAndSelectedIcon}"
icon.downAndSelected="{downAndSelectedIcon}"
icon.disabledAndSelected="{disabledAndSelectedIcon}" />
See this Apache mailing list thread for more discussion on this.
Try as I may, I am not able to skin a spark Button, when I place the button within a spark dataGrid. I am constrained to using the halo theme.
I have created the button renderer in a separate mxml file; I have separate buttons outside the dataGrid that show the skin correctly, so I am sure that there is nothing wrong with the skin. The whole point of this is to use the same skin inside the dataGrid as outside
The following code shows the same behavior that I am seeing; in this case the renderer is created in line. It seems like the skinClass is not respected. Or is there another way to do it.
<s:DataGrid id="dg" width="500" dataProvider="{employees2}">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="name" headerText="Name">
<s:itemRenderer>
<fx:Component>
<s:GridItemRenderer>
<s:Button label="Press Me"
top="0" bottom="0" left="0" right="0"
skinClass="MyButtonSkin" />
</s:GridItemRenderer>
</fx:Component>
</s:itemRenderer>
</GridColumn>
</s:ArrayList>
</s:columns>
</s:DataGrid>
In file MyButtonSkin.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:SparkButtonSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
minWidth="21" minHeight="21"
alpha.disabled="0.5">
<fx:Metadata>
<![CDATA[
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.Button")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling">
<![CDATA[
/* 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"];
/**
* #private
*/
override public function get colorizeExclusions():Array {return exclusions;}
/**
* #private
*/
override protected function initializationComplete():void
{
useChromeColor = true;
super.initializationComplete();
}
]]>
</fx:Script>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<!-- layer 2: fill -->
<!--- #private -->
<s:Rect id="fill" left="1" right="1" top="1" bottom="1" radiusX="10">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFAFAFA"
color.over="0xBBBDBD"
color.down="0xAAAAAA"
alpha="0.85" />
<s:GradientEntry color="0x808080"
color.over="0x9FA0A1"
color.down="0x929496"
alpha="0.85" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<!-- layer 8: text -->
<!--- #copy spark.components.supportClasses.ButtonBase#labelDisplay -->
<s:Label id="labelDisplay"
textAlign="center"
maxDisplayedLines="1"
horizontalCenter="0" verticalCenter="1" verticalAlign="middle">
</s:Label>
</s:SparkButtonSkin>
It appears that scaling the button to the size of the grid item does not size the corner radius.
I ended up with a button 200x200 pixels with a corner radius of 6 pixels; it just couldn't be seen. I upped the value to 25 and now I can see it
I'm trying to create a Panel skin (Spark) with a background fill color I can pass as a parameter.
(See in bold:)
<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin name="CustomPanelSkin"
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">
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
<s:State name="normalWithControlBar" stateGroups="withControls" />
<s:State name="disabledWithControlBar" stateGroups="withControls" />
</s:states>
<fx:Metadata>
[HostComponent("spark.components.Panel")]
</fx:Metadata>
<s:Group left="0" right="0" top="0" bottom="0">
<s:Rect left="0" right="0" top="0" bottom="0" radiusX="12" radiusY="12">
<s:fill>
<s:SolidColor color="#184c81" />
</s:fill>
</s:Rect>
<s:Group id="contents" left="1" right="1" top="1" bottom="1">
<s:layout>
<s:VerticalLayout gap="0" horizontalAlign="justify" />
</s:layout>
<s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0">
</s:Group>
</s:Group>
</s:Group>
</s:SparkSkin>
From what I read I should create a subclass, but there is not much material on the subject.
I would later on want to use this skin in many Panel controls I have in my application.
Base Panel skin has background color implementation using css styles. You can set it using action script:
panel.setStyle("backgroundColor", 0x184c81);
Also you can control skin components when you have a reference to it in the host component.
Read Implementing the partAdded() and partRemoved() methods for skinnable components for Spark components
This is simple.Create a panel skin and name it something as "panelSkin.mxml".In the .as file use the following statement
newPanelBlock.setStyle("skinClass",com.foldername.panelSkin);
newPanelBlock.setStyle("backgroundColor", 0x184c81);
I have a photo in a Flex project:
<s:Image source="#Embed('images/photo.png')" />
But now I'm wondering if I can make this image as the image below, in Flex (4 / 4.5 / 4.6) (in MXML and/or ActionScript 3):
Is this possible?
Here's a feathering mask tutorial in flash that you should be able to port to Flex.
Yes it is possible, first you need to create a mask layer for the rounder corners and inner shadow using AI or PS
Create a mask in Photoshop or AI. If you're using PS, it must be a vector mask.
Import it to Flash catalyst. If you're using PS, you must chose "Shape Layers > Keep Editable" in the import dialog.
In the layers panel, you'll see a Group with your masked content inside of it. Anything that goes inside that group will be masked.
Add the one image inside the masked group and copy the masked code in code view of Flash catalyst. (FC)
Now create one skin class for the spark image and add the mask code above the imageDisplay (BitmapImage).
MaskedImageSkin.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"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
alpha.disabled="0.5">
<s:states>
<s:State name="uninitialized" />
<s:State name="loading"/>
<s:State name="ready" />
<s:State name="invalid" />
<s:State name="disabled" />
</s:states>
<fx:Script fb:purpose="styling">
<![CDATA[
/**
* #private
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
{
// Push backgroundColor and backgroundAlpha directly.
// Handle undefined backgroundColor by hiding the background object.
if (isNaN(getStyle("backgroundColor")))
{
background.visible = false;
background.includeInLayout = false;
}
else
{
background.visible = true;
background.includeInLayout = true;
bgFill.color = getStyle("backgroundColor");
bgFill.alpha = getStyle("backgroundAlpha");
}
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
]]>
</fx:Script>
<!-- host component -->
<fx:Metadata>
<![CDATA[
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.Image")]
]]>
</fx:Metadata>
<!--- Defines the appearance of the image background. -->
<s:Rect id="background" left="0" right="0" top="0" bottom="0">
<s:fill>
<!-- #private -->
<s:SolidColor id="bgFill"/>
</s:fill>
</s:Rect>
<s:Group x="0" y="0">
<s:filters>
<s:DropShadowFilter color="#FFFFFF" inner="true" blurX="10" blurY="10" quality="5" alpha="0.85" angle="45" distance="10" />
<s:DropShadowFilter color="#FFFFFF" inner="true" blurX="10" blurY="10" quality="5" alpha="0.85" angle="90" distance="10"/>
<s:DropShadowFilter color="#FFFFFF" inner="true" blurX="10" blurY="10" quality="5" alpha="0.85" angle="-45" distance="10" />
<s:DropShadowFilter color="#FFFFFF" inner="true" blurX="10" blurY="10" quality="5" alpha="0.85" angle="-90" distance="10"/>
</s:filters>
<s:mask>
<s:Group x="0" y="0" width="280" height="180" >
<s:Rect left="0" right="0" top="0" bottom="0" radiusX="10" radiusY="10">
<s:fill>
<s:SolidColor color="#FFFFFF"/>
</s:fill>
</s:Rect>
</s:Group>
</s:mask>
<!--- Primary image display skin part. -->
<s:BitmapImage id="imageDisplay" left="0" top="0" right="0" bottom="0"/>
</s:Group>
<!--- Progress indicator skin part. -->
<s:Range id="progressIndicator" skinClass="spark.skins.spark.ImageLoadingSkin" verticalCenter="0" horizontalCenter="0" includeIn="loading" layoutDirection="ltr" />
<!--- Icon that appears in place of the image when an invalid image is loaded. -->
<s:BitmapImage id="brokenImageIcon" includeIn="invalid" source="#Embed(source='Assets.swf',symbol='__brokenImage')" verticalCenter="0" horizontalCenter="0"/>
</s:Skin>
Apply this skin class for spark image
<s:Image source="#Embed('assets/maskImg.png')" skinClass="MaskedImageSkin" width="200" height="200"/>
The above code is just an example of masking image, create your own mask using rounded rectangle. This will solve your issue.
Happy skinning ...
hostComponent seems to have stopped working as it used to before. If I create a custom comp based on lets say SkinnableContainer and apply default skin I am unable to see co hinting for Bindable/public variables from the skin. Code below to illustrate.
What am I missing here? Same seems to happen with other components/skins. I'm using latest Flash Builder (4.6).
<--------- Component --------------->
<?xml version="1.0" encoding="utf-8"?>
<s:SkinnableContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="400" height="300" skinClass="skins.testSkin">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
[Bindable]
public var test:String = "Test";
]]>
</fx:Script>
</s:SkinnableContainer>
<----------------- Skin -------------->
<?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"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled="0.5">
<fx:Metadata>
<![CDATA[
/**
* #copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.SkinnableContainer")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling">
<![CDATA[
/**
* #private
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
{
this.hostComponent
// Push backgroundColor and backgroundAlpha directly.
// Handle undefined backgroundColor by hiding the background object.
if (isNaN(getStyle("backgroundColor")))
{
background.visible = false;
}
else
{
background.visible = true;
bgFill.color = getStyle("backgroundColor");
bgFill.alpha = getStyle("backgroundAlpha");
}
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<!--- Defines the appearance of the SkinnableContainer class's background. -->
<s:Rect id="background" left="0" right="0" top="0" bottom="0">
<s:fill>
<!--- #private -->
<s:SolidColor id="bgFill" color="#FFFFFF"/>
</s:fill>
</s:Rect>
<!--
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" left="0" right="0" top="0" bottom="0" minWidth="0" minHeight="0">
<s:layout>
<s:BasicLayout/>
</s:layout>
</s:Group>
</s:Skin>
In order for Flash Builder to be able to provide you with code hinting for the public methods and properties of a custom component, the custom component needs to be specified in the HostComponent metadata directive within the skin. Currently, the skin code you provided has:
[HostComponent("spark.components.SkinnableContainer")]
Try changing that to whatever your custom component is, eg. com.mydomain.MyComponent.