Friday, July 13, 2007

Making Custom Chrome AIR Applications — A Tutorial

So you’ve probably tried playing around with Adobe Integrated Runtime (AIR) and had an idea to make a custom chrome application. A custom chrome application is one that does not use the typical operating system-provided chrome or application control window. As a result, is does not have standard controls, for example, to close or move the application window. At first glance creating a custom chrome application seems easy but it turns out to be a bit harder than it looks.

This tutorial assumes you are somewhat familiar with Flex programming (MXML and ActionScript) and have already installed the Flex Builder 2.01 and AIR extensions. If you’ve not done this, please visit Adobe Labs.

There are two important files you will have to work with to make your application chromeless. The first is the core AIR application, the second is the *-app.xml application descriptor file. This file is usually in the same directory as your base application. Go through the steps of setting up a new AIR project by selecting “File -> New –> AIR Project” from the Flex Builder Menu. Give your project a name (I called mine AIR_CustomChrome) and click “Finish”. You should have a file directory in the Navigator pane of your project that looks similar to this:







1. After you have set up a new project, you should be able to see the default code as follows:



<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<!--THIS IS WHERE TO ADD CODE-->
</mx:WindowedApplication>
 

2. In your *.MXML file, add the following lines of code to make the application. Insert them just below the “THIS IS WHERE TO ADD CODE” line:

<mx:TitleWindow id="mainPanel" backgroundColor="#0326FD" layout="absolute" cornerRadius="15" alpha="1.0" color="#FFFEFE" width="465" height="160" backgroundAlpha="0.7" borderColor="#1FBDF7" themeColor="#2FE7FD" x="0">

<mx:Label text="Look mom - no chrome!" width="400" textAlign="center" fontFamily="Verdana" fontSize="15" fontWeight="bold" x="22.5" y="10"/>

</mx:TitleWindow>
 

3. Test your application by running it. It should look like the image below. This application uses the system chrome, so on a Macintosh computer it will have the three little colored buttons on the top left and an application window to house the application.



4. Next, we are going to lose the system chrome. Open up the AIR_CustomChrome-app.xml file and locate the following line of code:


<rootContent systemChrome="standard" transparent="false" visible="true">[SWF reference is generated]</rootContent>
 

…and change it as follows (the parts highlighted in bold font) before saving and closing the file:


<rootContent systemChrome="none" transparent="true" visible="true">[SWF reference is generated]</rootContent>
 


This tells the runtime not to use system chrome and that the application has support for transparency.
You might think this would be enough but it is not.

If you run the application again, you will get an application that looks like the one below. Not only are you still stuck with chrome, but it is even uglier than before. We can fix this in the next steps.




5. The cause of this is the root element used by default by AIR. This element is the <mx:windowedapplication> tag. Change both the opening and closing tags to <mx:application> Your code should look something like this now:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" height="202" width="483">
<mx:TitleWindow id="mainPanel" backgroundColor="#0326FD" layout="absolute" cornerRadius="15" alpha="1.0" color="#FFFEFE" width="100%" height="100%" backgroundAlpha="0.7" borderColor="#1FBDF7" themeColor="#2FE7FD" x="0" >

<mx:Label text="Look mom - no chrome!" width="400" textAlign="center" fontFamily="Verdana" fontSize="15" fontWeight="bold" x="22.5" y="10"/>
</mx:TitleWindow>
</mx:Application>
 

…and it will yield the application below when run.

This is somewhat problematic as we have almost rid ourselves of the standard native window but have not yet introduced functionality to replace the standard chrome for things like moving or closing the application. To close the application you will have to use native operating system methods (for example on a Mac, highlight the app then hit Command-Q)



6. Note that the top right and left corners still have a tiny bit of gray color around the edges. This is still the default application window showing itself. To get rid of this, we have to introduce some lines of CSS inside the tag. Add these lines of code to your application just below the root tag.


<mx:Style>
Application
{
/*make app window transparent*/
background-color:"";
background-image:"";
padding: 0px;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
}
</mx:Style>

 

This code sets the style for the Application component (now your root element) and will remove the gray. When you run the application again, it will be gone. Your application will also be semi-transparent as shown below.



7. We still have no way to move or close the application. In order to do this, we have to introduce some simple scripting elements. Start by adding a <mx:script> tag just below your <mx:style> tag and add the following lines of code:


<mx:Script>
<![CDATA[
import flash.display.Bitmap;

public function init():void {

// Move the app when the panel is dragged
mainPanel.addEventListener( MouseEvent.MOUSE_DOWN, startMove );

}

public function startMove(event:MouseEvent):void {
stage.window.startMove();
}
]]>
</mx:Script>

 

…and add the following method call to the root element:


creationComplete="init()"
 


…to call the init() function when the application starts up. When you run the application now, you can move it on your screen by clicking on it and dragging it.


8. We will want to add the ability to close the application. Luckily, the TitleWindow element has a built in close button. Add the following attributes to the <mx:titledwindow> element:


showCloseButton="true" close="closeEvent(event)"
 

9. Now that we have added the Close button, we have to import the ability to detect the CloseEvent. Add the following line of code in the <mx:script> element to import this functionality:


import mx.events.CloseEvent;
 

…then add the following function to your code base.


public function closeEvent(event:CloseEvent):void {
stage.window.close();
}
 

Your complete code should now look like this:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
xmlns:utils="utils.*" creationComplete="init()" height="160" width="465" >

<mx:Style>
Application
{
/*make app window transparent*/
background-color:"";
background-image:"";
padding: 0px;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
}
</mx:Style>

<mx:Script>
<![CDATA[
import flash.display.Bitmap;
import mx.events.CloseEvent;

public function init():void {

// Move the app when the panel is dragged
mainPanel.addEventListener( MouseEvent.MOUSE_DOWN, startMove );

}
public function startMove(event:MouseEvent):void {
stage.window.startMove();
}

public function closeEvent(event:CloseEvent):void {
stage.window.close();
}
]]>

</mx:Script>

<mx:TitleWindow id="mainPanel" backgroundColor="#0326FD" layout="absolute" cornerRadius="15" alpha="1.0"
color="#FFFEFE" width="465" height="160" backgroundAlpha="0.7" borderColor="#1FBDF7" themeColor="#2FE7FD"
x="0" showCloseButton="true" close="closeEvent(event)">

<mx:Label text="Look mom - no chrome!" width="400" textAlign="center" fontFamily="Verdana" fontSize="15" fontWeight="bold" x="22.5" y="10"/>
<mx:Label x="62.5" y="92" text="(c) Duane Nickull - samples at technoracle.blogspot.com"/>
</mx:TitleWindow>
</mx:Application>
 

Your application will now be chromeless and it actually can be closed by clicking on the Close button in the top right hand corner.

26 comments:

  1. You should extend this to also include resize-ability.

    ReplyDelete
  2. Great step-by-step walk through. How about an app with multiple windows?

    ReplyDelete
  3. What about odd shaped windows? For example, an apple shape.

    ReplyDelete
  4. Hehe - your challenge was taken. I created an Apple shaped application and tutorial here - http://technoracle.blogspot.com/2007/07/air-apple-shaped-application.html

    ReplyDelete
  5. Keep getting an error message with the following code.

    close="closeEvent(event)"

    Using Flex Builder 2.0.1

    Copied all of the code and still received the following error.

    "Call to a possibly undefined method closeEvent."

    ReplyDelete
  6. Please disregard the posting about the error. Found my mistake.

    Thanks for sharing the Chromeless tutorial.

    ReplyDelete
  7. Great and nice to follow tutorial, gave me a bit more of an insight around AIR. Thanks a lot for a great tutorial, wish there were more of those :)

    ReplyDelete
  8. Hey Duane, thanks a bunch for this tutorial, "as already mentioned before :)

    I've now built a complete application inside of the title window with various sliders inside, as soon as click on a slider, the whole window moves, I undestand why, but I have no clue how to fix it, so only the header of the app can be dragged.
    Any ideas? Thanks Tiago

    ReplyDelete
  9. Please send me your code to dnickull (at) adobe dot com and I'll try to help.

    Duane

    ReplyDelete
  10. You should extend this to also include resize-ability.

    ReplyDelete
  11. this is helpful, but if you change the WindowedApplication to Application, you can no longer resize the stage by setting stage.stageHeight=numValue;

    ReplyDelete
  12. You don't have to change the main application tag. All you need to do is set an attribute called showFlexChrome to false - like so showFlexChrome="false" on the WindowedApplication tag

    ReplyDelete
  13. Gregory:

    Yes you are correct now. In the version I had you couldn't use that attribute when I created this. I wonder if I should change the blog post or simply leave this comment.

    ReplyDelete
  14. with the eminent release of m5, Beta 2 - this custom chrome should be going away completely. though it may not be till version 1.0 of AIR that isn't completely gone.

    ReplyDelete
  15. Hi! Nice site.

    ReplyDelete
  16. This comment has been removed by a blog administrator.

    ReplyDelete
  17. This comment has been removed by a blog administrator.

    ReplyDelete
  18. This comment has been removed by a blog administrator.

    ReplyDelete
  19. The previous three comments were deleted as they were spam placed here by cowards and criminals. All - please beat these spammers with blunt objects if you encounter them or point their identities out to me so I might strangle them.

    ReplyDelete
  20. Hi..

    Your blog is AWESOME!! To be honest you are my ROLE MODEL!!! I am working on my blog for which I want to get a good PR..(A challenge with my FRIENDS).. If you don't mind can you please tell me the things that make my DREAM come TRUE!!

    ReplyDelete
  21. Hi Bharath:

    Thank you. I am humbled as I feel I am still learning the blog stuff. I have made a lot of mistakes but have learned some basic rules that seem to work. Here are some of the things I think might be relevant:

    1. Blog regularly so people have a reason to come back.
    2. Give to the community - provide code samples, explanations, workarounds which are relevant to what developers (or your target audience) want to know.
    3. Make everything you post open source and IP unrestricted.
    4. Answer comments from people (like right now) on a timely manner.

    I hope this helps. Please let me know when your blog is up and running and feel free to copy any materials you want from this blog.

    Duane

    ReplyDelete
  22. This comment has been removed by a blog administrator.

    ReplyDelete
  23. The previous link was deleted as it was SPAM.

    ReplyDelete
  24. UPDATE:

    This tutorial is a bit dated. I will be making a new one to correspond with Flex Builder 3 and AIR 1.1

    Duane

    ReplyDelete
  25. In Flex 3 it works quite the same, the only difference is that the visible property needs to be set to true (default is false for some reason...).

    ReplyDelete
  26. Here's a tutorial for Flex3 for those interested:

    http://mysticnomad.wordpress.com/2008/09/08/creating-a-custom-chrome-for-air-application/

    ReplyDelete

Do not spam this blog! Google and Yahoo DO NOT follow comment links for SEO. If you post an unrelated link advertising a company or service, you will be reported immediately for spam and your link deleted within 30 minutes. If you want to sponsor a post, please let us know by reaching out to duane dot nickull at gmail dot com.