5

In Flex it is now possible to use the -define compiler option to do all sorts of cool stuff. In my program, I am using the option such that some of my code is excluded by blocks like this:

CONFIG::FACEBOOK{
   //Some code
}

And this is working well.

How do I get a similar behaviour with MXML?

I want to do the same thing, but omitting/including MXML tags in this way, not blocks of AS code.

3 Answers3

2

My solution is to add some tags that could help to comment out unnecessary blocks of mxml code in certain build. For example I want to add different buttons in Android and iOS builds:

<!-- iOS --><!--
<s:Button id="backBtn" 
    icon="{SHOW_LIST}" 
    click="navigator.popView()"/>
--><!-- /iOS -->

<!--Android-->
<s:Button id="exitBtn" 
    label="Exit" 
    click="NativeApplication.nativeApplication.exit()"/>
<!--/Android-->

Now run simple batch script which will comment out all Android specific code in the source for iOS build

PrepareForIos.cmd

@echo off
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--Android-->" "<!-- Android --><!--"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--/Android-->" "--><!-- /Android -->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!-- iOS --><!--" "<!--iOS-->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "--><!-- /iOS -->" "<!--/iOS-->"
pause

FART is a command-line tool for finding and replacing strings

Now our code looks like this and is ready to be built for iOS:

<!--iOS-->
<s:Button id="backBtn" 
    icon="{SHOW_LIST}" 
    click="navigator.popView()"/>
<!--/iOS-->

<!-- Android --><!--
<s:Button id="exitBtn" 
    label="Exit" 
    click="NativeApplication.nativeApplication.exit()"/>
--><!-- /Android -->

Inverse operation batch:

PrepareForAndroid.cmd

@echo off
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--Android-->" "<!-- Android --><!--"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--/Android-->" "--><!-- /Android -->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!-- iOS --><!--" "<!--iOS-->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "--><!-- /iOS -->" "<!--/iOS-->"
pause
EugeneK
  • 57
  • 3
1

A trick I use is to create a static class that holds constants for the different builds:

package 
{
    public class MyAppConstants
    {
        CONFIG::Debug
            public static const DEBUG:Boolean = true;           
        CONFIG::Release
            public static const DEBUG:Boolean = false;
    }
}

And then I use these constants in my MXML:

<namespace:component visible="{MyAppConstants.DEBUG}" includeInLayout="{MyAppConstants.DEBUG}"/>

This will make sure the component is not added to the display list and thusly not measured either. If you would only use the visible attribute the dimensions of the component are still taken into account and will therefore leave "empty" spaces.

Tox
  • 373
  • 4
  • 13
  • Would it not work to just write `` ? – Gene Pavlovsky Jul 21 '16 at 10:37
  • 1
    It might, haven't tested it. But I expect it to **not** evaluate the `CONFIG::DEBUG` constant and instead pass it as `String` to the attributes. If you wrap them in curly braces, it might work. I used the static constants class for convenience. Those you can easily refactor if you change a name, the `CONFIG::*` constants need to be manually replaced and you don't get proper error messages if you forget one, so it's more error prone. – Tox Jul 22 '16 at 11:37
  • Good points. I've gone your route as well, as I had to also reference them in plain AS classes, and my IDE (FlashDevelop) doesn't offer code completion for CONFIG::* constants. – Gene Pavlovsky Jul 22 '16 at 23:20
  • 1
    FlashBuilder doesn't have code completion for compile time constants either. They are useful, but sometimes a pain to work with. – Tox Jul 31 '16 at 08:45
  • I don't know if anyone still uses this/cares, but maintaining an older project, I've just found out this works: ` – Gene Pavlovsky Apr 10 '20 at 18:15
0

Edited response, based on this comment:

Sorry for being slow to get back to this thread. My intention was to have some interface elements (Buttons, and the like) which were omitted in some builds and included in others. My current workaround is to simply set the visible property of the component to the compiler defined boolean constant - it's crude, but it works. Any thoughts on a better way? – Chris Kitching Sep 20 at 14:40

I think you might be able to use the deferred initialisation behaviour of flex to control which components are created and added to your parent component - it might be a little against the idea of MXML, but I think it's possible.

Here is a bit of background on manually initialising deferred components (for spark and mx components):
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7aee.html

Flex 3

If you're using Flex 3 then you can override the createComponentsFromDescriptors() method and access the childDescriptors property to control exactly which child MXML components will be created.

The Creating deferred components article shows how you can get information about an MXML component from the descriptor. You could use this behaviour to determine which components should or shouldn't be instantiated for the current build.

Class reference for UIComponentDescriptor: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponentDescriptor.html

Flex 4

In Flex 4 it's a little less clear - all MXML components will be created from their descriptors (there isn't a childDescriptors property, just the mxmlContentFactory instance which will create all of the children).

Two options for controlling the display of MXML components might be:

  1. Override the createDeferredContent() method and initialise the child components with the mxmlContentFactor but remove elements from the returned array before setting the mxmlContent property (which adds them to the display list).

  2. Implement a template component that defines exactly what type of components are allowed as children, and only initialising the appropriate children for your current build type.
    Here is an example of creating a template component in this way: Using IDeferredInstance in a template component.

Hopefully that gives you something to think about, and hopefully it's not too complicated :)


Original answer:

The short answer is that you can't use conditional compilation for MXML tags. All MXML tags will be compiled into the component.

What are your goals in wanting to use conditional MXML?

Are you trying to include/exclude classes based on the compiler properties but still keep the short-hand MXML declarations? i.e. not have to define everything in actionscript.

With a bit more info we might be able to work through to an acceptable alternative :)

Sly_cardinal
  • 12,270
  • 5
  • 49
  • 50
  • Sorry for being slow to get back to this thread. My intention was to have some interface elements (Buttons, and the like) which were omitted in some builds and included in others. My current workaround is to simply set the visible property of the component to the compiler defined boolean constant - it's crude, but it works. Any thoughts on a better way?> – Chris Kitching Sep 20 '11 at 14:40