How to add OSX / minimalist scrollbars

If you use a Mac and OSX Lion you’ll notice the scroll bars have changed to a simple line or track similar to what Flash sites have been using. You can get the same look and feel in your Flex Spark projects using this skin class. Demo and source is at the link.

Posted in Flex | Leave a comment

How to declare a component or skin inline

I’ve wanted to know how to do this for a while and I couldn’t get it to work until now. Here’s how how to set the skin class to the skin declared in the declarations.

<?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="{mySkinClass}">

	<fx:Declarations>
		<fx:Component className="mySkinClass">
			<s:Skin >
				<s:states>
					<s:State name="normal" />
					<s:State name="disabled" />
					<s:State name="normalWithControlBar" stateGroups="withControls" />
					<s:State name="disabledWithControlBar" stateGroups="withControls" />
				</s:states>
				<s:Button label="HELLO SKIN"/>
			</s:Skin>
		</fx:Component>
	</fx:Declarations>

</s:SkinnableContainer>

Note: It’s not “inline” as an item renderer is inline but it’s in the same document which is close enough for me. :)

Example II

	<s:ButtonBar id="buttonBarList"
				 top="120"
				 width="100%"
				 height="40"
				 skinClass="{MyButtonBarSkin}"
				 >

	</s:ButtonBar>

	<fx:Declarations>
		<fx:Component className="MyButtonBarSkin">
			<skins:ButtonBarSkin>

			</skins:ButtonBarSkin>
		</fx:Component>
	</fx:Declarations>

NOTE: When declaring a skin class you may have to manually add the namespace to the package path to the document since it is not in the default manifest. You can do that like this:

<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
		xmlns:s="library://ns.adobe.com/flex/spark"
		xmlns:skins="spark.skins.mobile.*"
		>

Notice how we point right to the package path that has our skin class into it. This also works for every other class that is not showing up automatically in code hinting.

Posted in Flex | Leave a comment

Understanding FXG with a vector based button example

This post will show the FXG code generated from Illustrator of creating a button with vector based artwork from start to finish. For this post we’ll be creating a circular button with a transparent gradient on top. You will see code for an Ellipse, Rectangle, Solid Color Fill, Linear Gradient, transparent gradient, rotation of the gradient, scale of the gradient, the start location of the gradient, applying a mask and fixing the code so our graphic element can be scaled to any size and keep our sharp vector graphics and original aspect ratio.

But first let’s look at an FXG code that is exported from a blank artboard in Illustrator.

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" viewHeight="792" viewWidth="612" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
  <Library/>
  <Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1"/>
  <Private/>
</Graphic>

Notice the viewHeight and viewWidth property in the Graphic tag.

Creating the circle or Ellipse (An Ellipse is a filled circular graphic element.).

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" viewHeight="792" viewWidth="612" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
  <Library/>
  <Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
    <Group ai:seqID="2" d:type="layer" d:userLabel="Layer 3">
      <Ellipse width="100" height="100" ai:seqID="3">
        <fill>
          <SolidColor color="#FF0000"/>
        </fill>
      </Ellipse>
    </Group>
  </Group>
  <Private/>
</Graphic>

The Ellipse above is 100 x 100. In Illustrator it has been placed at 0×0 position on the artboard. This position is relative to the center of the Ellipse not the upper left hand corner (so from the middle of Ellipse at 0×0 half off it is off the artboard). When you are creating content in Illustrator position it in the upper left corner of the artboard. This location is called the registration point. Note: For this example we are not applying any transformations to the image. It is important to know that transformations work with the registration point.  See http://en.wikipedia.org/wiki/Image_registration

To see what this looks like create a new Flex project and paste the code above into a new file called “circleAI.fxg”. Then add it to the Application like so:

<?xml version="1.0" encoding="utf-8"?>
<s:rApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:local="*">

	<local:circleAI >

</s:Application>

If that’s all you wanted to do then that will work. But if you set any dimensions on it such as 200×200 then you will notice that becomes skewed.

<?xml version="1.0" encoding="utf-8"?>
<s:rApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:local="*">

	<local:circleAI width="200" height="200">

</s:Application>

The reason is that the viewWidth and viewHeight properties are defining the whole size of the artboard in Illustrator not the dimensions of the Ellipsis. We can fix this. Open up the circleAI.fxg file and remove those properties and try it again.

In the design of the button we have a linear gradient that fades into the background. To get a transparent gradient we must first create a mask.

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
  <Library/>
  <Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
    <Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
      <mask>
        <Group>
          <Rect width="100" height="100" ai:seqID="3">
            <fill>
              <SolidColor color="#FF0000"/>
            </fill>
          </Rect>
        </Group>
      </mask>
      <Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
        <Ellipse width="100" height="100" ai:seqID="5">
          <fill>
            <SolidColor color="#FF0000"/>
          </fill>
        </Ellipse>
      </Group>
    </Group>
  </Group>
  <Private/>
</Graphic>

This is the first part of creating the gradient. That is creating the mask. In the Group element above we have a property called mask. A mask is a stupid name for what it does. A mask is just a second graphic element that is used to define what areas should be visible in the layer it is part of. In the code above we use a rectangle for this purpose. Because we specified a mask everything in the Group is hidden. The only part of our original content that will be shown is the opaque pixels defined in our mask area. So since we have a fully opaque rectangle sized the same as the Ellipse our Ellipse is fully visible. If the rectangle was sized 50 x 50 then only the upper left quarter of the Ellipse would be visible.

BTW Notice all the additional namespaces in the code above. You can remove these and get a much cleaner looking code. However they don’t affect the result so we will leave them in.

Next we add a gradient to the fill of the rectangle.

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
  <Library/>
  <Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
    <Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
      <mask>
        <Group>
          <Rect width="100" height="100" ai:seqID="3">
            <fill>
              <LinearGradient x="0" y="50" scaleX="100">
                <GradientEntry ratio="0" color="#FFFFFF"/>
                <GradientEntry ratio="0.618104" color="#5A5A5A"/>
                <GradientEntry ratio="1"/>
              </LinearGradient>
            </fill>
          </Rect>
        </Group>
      </mask>
      <Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
        <Ellipse width="100" height="100" ai:seqID="5">
          <fill>
            <SolidColor color="#FF0000"/>
          </fill>
        </Ellipse>
      </Group>
    </Group>
  </Group>
  <Private/>
</Graphic>

The code above creates a gradient but it does not provide transparency. We can add transparency by setting the alpha property on the Gradient Entry.

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
  <Library/>
  <Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
    <Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
      <mask>
        <Group>
          <Rect width="100" height="100" ai:seqID="3">
            <fill>
              <LinearGradient x="0" y="50" scaleX="100">
                <GradientEntry ratio="0" color="#FFFFFF"/>
                <GradientEntry ratio="0.618104" color="#5A5A5A" alpha="0.381896"/>
                <GradientEntry ratio="1" alpha="0"/>
              </LinearGradient>
            </fill>
          </Rect>
        </Group>
      </mask>
      <Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
        <Ellipse width="100" height="100" ai:seqID="5">
          <fill>
            <SolidColor color="#FF0000"/>
          </fill>
        </Ellipse>
      </Group>
    </Group>
  </Group>
  <Private/>
</Graphic>

Notice the linear gradient X and Y. This is where it starts. Also notice the scaleX. This is how wide it is. If it is set to 100 percent and the width of the rectangle is 100 then the gradient is also 100.

Next you set the rotation on the gradient.

<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
  <Library/>
  <Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
    <Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
      <mask>
        <Group>
          <Rect width="100" height="100" ai:seqID="3">
            <fill>
              <LinearGradient x="0" y="100" scaleX="100" rotation="-90">
                <GradientEntry ratio="0" color="#FFFFFF"/>
                <GradientEntry ratio="0.618104" color="#5A5A5A" alpha="0.381896"/>
                <GradientEntry ratio="1" alpha="0"/>
              </LinearGradient>
            </fill>
          </Rect>
        </Group>
      </mask>
      <Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
        <Ellipse width="100" height="100" ai:seqID="5">
          <fill>
            <SolidColor color="#FF0000"/>
          </fill>
        </Ellipse>
      </Group>
    </Group>
  </Group>
  <Private/>
</Graphic>

When we do this the X and Y are also rotated as well. To maintain the gradient position we set the Y to 100.

              <LinearGradient x="0" y="100" scaleX="100" rotation="-90">
                <GradientEntry ratio="0" color="#FFFFFF"/>
                <GradientEntry ratio="0.618104" color="#5A5A5A" alpha="0.381896"/>
                <GradientEntry ratio="1" alpha="0"/>
              </LinearGradient>

If we want to use this in Flex as a button then create a new Skin and place the instances  inside. This button will scale and maintain it’s vector graphics irregardless of the width and height of the button.

<?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" xmlns:local="*">

    <fx:Metadata>
        [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:Rect width="100%" height="100%" alpha="0">
		<s:fill>
			<s:SolidColor color="0"/>
		</s:fill>
	</s:Rect>

	<local:circleFinal includeIn="up,over,disabled" width="100%" height="100%">
	</local:circleFinal>

	<local:circleFinalDown includeIn="down" width="100%" height="100%" >
	</local:circleFinalDown>

</s:SparkButtonSkin>

 

	<s:HGroup verticalCenter="0" horizontalCenter="0" verticalAlign="middle">

		<s:Button skinClass="MyButtonSkin"
				  width="100" height="100"/>

		<s:Button skinClass="MyButtonSkin"
				  width="150" height="150"/>
	</s:HGroup>

 

 

Posted in AIR, Flash, Flash Catalyst, Flex, FXG | Leave a comment

Creating a recessed line in MXML

I’ve been trying to get a recessed line type of look with MXML and since it took a while I’m posting it here. It can be improved so please post any updates.

	<s:Line width="100%" top="98" left="10" right="10">
		<s:stroke>
			<s:SolidColorStroke color="#555555" weight="1" caps="none"/>
		</s:stroke>
		<s:filters>

			<s:BevelFilter angle="45"
						   type="outer"
						   distance="1"
						   knockout="true"
						   highlightColor="#000000"
						   highlightAlpha=".5"
						   shadowColor="#ffffff"
						   shadowAlpha=".5"
						   blurX="3"
						   blurY="3"
						   />

		</s:filters>
	</s:Line>

I think the look I’m trying to go for is the horizontal rule in Visual Studio type GUI.

Here’s a slightly sharper alternative setting:

<s:BevelFilter angle="45"
						   type="outer"
						   distance="1"
						   knockout="true"
						   highlightColor="#000000"
						   highlightAlpha=".5"
						   shadowColor="#ffffff"
						   shadowAlpha=".5"
						   blurX="0"
						   blurY="0"
						   />
Posted in Flex | Leave a comment

Tips on using the TileLayout in Flex 4.6

Tips on using TileLayout in Flex 4.6. I had some difficulty in getting a tile layout to dynamically expand or contract the layout items. This post shows how I solved it.

To get the items in a TileLayout to expand to fill all the available space in a List or DataGroup container use the following settings:

<s:TileLayout id="tileLayout"
			  horizontalGap="20"
			  verticalGap="20"
			  orientation="columns"
			  requestedColumnCount="{columnCount}"
			  rowAlign="justifyUsingHeight"
			  columnAlign="justifyUsingWidth"
			  rowHeight="{list.height / list.dataProvider.length}"
			  />

The key is to set the rowHeight to minimum values based on the total number of items. In this case we are checking the list data provider and making sure the cell is at least that size.* In some cases it works fine without the rowHeight line???

When the columnAlign is set to ColumnAlign.JUSTIFY_USING_WIDTH the columnWidth actual value increases so that the last fully visible column right edge aligns with the container’s right edge. Note that explicitly setting the columnWidth property does not turn off justification. It only determines the initial column width value. Justification may increase it.

The columnCount is an integer with the value of 2. You can modify this value to fit your needs.

Note: To get all the contents of a layout item to use all available space set the verticalAlign and horizontalAligh to justify.

<s:TileLayout id="tileLayout"
			  horizontalAlign="justify"
			  verticalAlign="justify"
			  />

Whenever you set the column count the layout will be updated and the layout items resized.

	<s:List id="list"
			left="20"
			right="20"
			top="20"
			bottom="20"
			width="100%"
			height="100%"
			labelField="@label"
			selectedIndex="-1"
			contentBackgroundAlpha="0">
Posted in Flex | Leave a comment