Adjusting Component size in flex - apache-flex

I have a viewstack with 3 items in it. Now my problem is that I want all these components to be of the same size. Its simply enough to do this manually but is there any other way of setting the size for all the components at once?

You can probably set the 'left/right/top/bottom' styles for that items.

There are (roughly) two big-time ways to go about this that I see right off the bat:
Basically you bind those components' width values to one variable, and their height values to another variable. Use the same two variables for all of your components. For example:
<mx:Script>
<![CDATA[
[Bindable]
private var m_nWidth:Number = 50;
[Bindable]
private var m_nHeight:Number = 50;
private function someFunc():void
{
m_nWidth = 100;
m_nHeight = 200;
// uic1, uic2, and uic3 are all now 100 x 200
}
]]>
</mx:Script>
<mx:ViewStack id="vs">
<mx:UIComponent id="uic1" width="{m_nWidth}" height="{m_nHeight}"/>
<mx:UIComponent id="uic2" width="{m_nWidth}" height="{m_nHeight}"/>
<mx:UIComponent id="uic3" width="{m_nWidth}" height="{m_nHeight}"/>
</mx:ViewStack>
You could also set percentage-style strings on their width and height attributes, making them scale with regards to the size of the ViewStack. For example:
<mx:Script>
<![CDATA[
private static const WIDTH:String = "50%";
private static const HEIGHT:String = "25%";
private function someFunc():void
{
vs.width = 200;
vs.height = 800;
// uic1, uic2, and uic3 are all now 100 x 200
}
]]>
</mx:Script>
<mx:ViewStack id="vs">
<mx:UIComponent id="uic1" width="{WIDTH}" height="{HEIGHT}"/>
<mx:UIComponent id="uic2" width="{WIDTH}" height="{HEIGHT}"/>
<mx:UIComponent id="uic3" width="{WIDTH}" height="{HEIGHT}"/>
</mx:ViewStack>

not sure if you already got the answer
but what i read was that you could set the main application to be 100% for bott height and width. for the viewstack you set it as 100% also. it should resize the children accordingly
or you can use actionscript percentHeight and percentWidth to set the property

Related

How to splice 2 mx canvas objects with repeat-x backgrounds?

I have 2 canvas objects that both contain a tiling image. My client recently requested that both the images be able to appear at the same time. I simply allowed them to be both enabled at the same time thinking they would tile appropriately but they do not.
After some careful thought I realized this is because they are of varying width so although my tiling image is 7 pixels in width, it may not always end at 7 pixels thus causing it to not appear to tile cleanly.
I can't just lop off the remainders because the imagery is being used to assess quantities of items (without going into too much detail) and having item 1 with 97 quantity next to item 2 with 200 quantity on one row compared to row 2 with item 1 having 100 quantity and item 2 having 300 quantity will show up strange to the end-user.
Does anyone know of how I could get started with maybe splicing the two canvas objects together or rather using 1 canvas object and then using BOTH background images and setting a percentWidth or something that the other one comes into affect?
You can use the copyPixels() method of the BitmapData class to achieve this sort of result. To do this, you need to load each image with a Loader. When the images are loaded, you have two Bitmap objects. From there, you access the corresponding BitmapData for each Bitmap and can splice them together.
After the splice, you create a new Bitmap object from the combined BitmapData. Then you feed the combined Bitmap to some other component. Unfortunately, a Canvas won't accept a Bitmap for its backgroundImage style. But you can add the combined Bitmap to a UIComponent or set it as the source of an Image component.
Finally, add either the UIComponent or Image to a Canvas. Since you can layer things on the Canvas, you effectively have a background image as long as place (and leave) the combined image at index 0 of the Canvas.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
minWidth="955" minHeight="600"
creationComplete="onCreationComplete()">
<mx:Script>
<![CDATA[
import mx.containers.Canvas;
import mx.controls.Image;
import mx.core.UIComponent;
import mx.events.FlexEvent;
private var loader1:Loader;
private var loader2:Loader;
private var bitmap1:BitmapData;
private var bitmap2:BitmapData;
protected function onCreationComplete():void
{
loader1 = new Loader();
loader1.load(new URLRequest("Android_Robot_100.png"));
loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader1Complete, false,0,true);
loader2 = new Loader();
loader2.load(new URLRequest("rails.png"));
loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader2Complete, false,0,true);
}
protected function onLoader1Complete(event:Event):void
{
bitmap1 = (loader1.content as Bitmap).bitmapData;
if (bitmap1 && bitmap2)
copyPixels();
}
private function onLoader2Complete(event:Event):void
{
bitmap2 = (loader2.content as Bitmap).bitmapData;
if (bitmap1 && bitmap2)
copyPixels();
}
protected function copyPixels():void
{
// false = non-transparent background
var combined:BitmapData = new BitmapData(200,200, false);
var sourceRect1:Rectangle = new Rectangle(0,0,bitmap1.width, bitmap1.height);
var sourceRect2:Rectangle = new Rectangle(0,0,bitmap2.width, bitmap2.height);
combined.copyPixels(bitmap1, sourceRect1, new Point(0,0));
combined.copyPixels(bitmap2, sourceRect2, new Point(bitmap1.width, 0));
var result:Bitmap = new Bitmap(combined);
var image:Image = new Image();
image.source = result;
var canvas:Canvas = new Canvas();
canvas.addChildAt(image, 0);
addChild(canvas);
// as an alternative, just add the bitmap to a UIComponent
// note you can't do this and the above at the same time,
// becuase the 'result` Bitmap can only be the child of one
// object, adding it to one thing removes it from the other...
// var uic:UIComponent = new UIComponent();
// uic.addChild(result);
// addChild(uic);
}
]]>
</mx:Script>
</mx:Application>
Ultimately I was overcomplicating it. I simply did this with masking like...
<mx:Canvas width="100%" height="100%">
<mx:Image id="myFirstUnrelatedImage" width="50%" height="65%" maintainAspectRatio="false"
verticalCenter="0" left="3"
source="#Embed('../assets/image1.png')" visible="true"/>
<!-- not sure why borderStyle here is required but it won't show up without? -->
<mx:Canvas id="image1mask" width="30%" height="94%"
borderStyle="none" visible="false"/>
<mx:Canvas id="image1" width="100%" height="100%"
minWidth="0" styleName="myStyle"
mask="{image1mask}"/>
<!-- not sure why borderStyle here is required but it won't show up without? -->
<mx:Canvas id="image2mask" width="20%" height="94%"
right="0" borderStyle="none" visible="false"
includeInLayout="false"/>
<mx:Canvas id="image2" width="100%" height="100%"
minWidth="0" styleName="myStyle2"
mask="{image2mask}"/>
</mx:Canvas>
Where my styles were controlling the backgroundImage and backgroundRepeat properties in css.

How to clear the explicit width and height of a Group

I have a group that sizes to the contents it contains but to perform a transition using Tweener I have to set the width and height properties. After the animation is done how would I clear the explicit width and height properties so that the Group goes back to sizing based on it's contents?
Before:
<s:Group ><content.../></s:Group>
Code:
width = 250;
height = 250;
Tweener.addTween(this, {width:500, height:500, time:0.25, onComplete:openAnimationComplete});
After the tween the Group is effectively set to 500x500 as if it were this:
<s:Group width="500" height="500" ><content /></s:Group>
I want it to return to this:
<s:Group ><content /></s:Group>
UPDATE
Test code using solution from Flextras:
<fx:Script>
<![CDATA[
protected function button1_clickHandler(event:MouseEvent):void
{
var w:Object = myGroup.width;
var h:Object = myGroup.height;
if (myGroup.width!=300) {
myGroup.width = 300;
myGroup.height = 300;
}
else {
myGroup.width = NaN;
myGroup.height = NaN;
w = myGroup.width; // NaN
h = myGroup.height; // NaN
//myGroup.validateNow()
if (myGroup.parent is IInvalidating) {
IInvalidating(myGroup.parent).validateNow();
}
w = myGroup.width; // 600
h = myGroup.height; // 100
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Group id="myGroup" minHeight="0" minWidth="0" clipAndEnableScrolling="true">
<s:Button width="600" height="100" label="here is a button" click="button1_clickHandler(event)"/>
</s:Group>
Set the height and width to NaN; which would effectively tell the Flex Framework "I have no idea what this value is" and will then execute the measure() event during the next time the component renders itself; causing it to update the measuredHeight and measuredWidth properties; which will in turn be used by the parent container to size the group.

Simulate includeInLayout=false in pure Actionscript code

If you know Flex, you probably know what the property "includeInLayout" does. If not, this property make the parent of your component disregard the bounds (like width and height) of your component in render their own bounds.
Description in reference below:
Specifies whether this component is
included in the layout of the parent
container. If true, the object is
included in its parent container's
layout and is sized and positioned by
its parent container as per its layout
rules. If false, the object size and
position are not affected by its
parent container's layout.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#includeInLayout
In Flex, for example:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="application1_creationCompleteHandler(event)">
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function application1_creationCompleteHandler( event:FlexEvent ):void
{
trace( container.width, container.height ); // output: 200 200
}
]]>
</mx:Script>
<mx:Canvas id="container">
<mx:Button label="Test"
width="100"
height="100" />
<mx:Button label="Test2"
width="200"
height="200" />
</mx:Canvas>
</mx:Application>
Now if I set includeInLayout="false" in second button:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="application1_creationCompleteHandler(event)">
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function application1_creationCompleteHandler( event:FlexEvent ):void
{
trace( container.width, container.height ); // output: 100 100
}
]]>
</mx:Script>
<mx:Canvas id="container">
<mx:Button label="Test"
width="100"
height="100" />
<mx:Button label="Test2"
width="200"
height="200"
includeInLayout="false" />
</mx:Canvas>
</mx:Application>
I know of all framework architecture involved to implement this property and know than this property is a property from Flex Framework. What I wanna is this behavior in pure actionscript. For example:
import flash.display.Shape;
var myBox:Shape = new Shape();
myBox.graphics.beginFill(0xFF0000);
myBox.graphics.drawRect(0, 0, 100, 100);
myBox.graphics.endFill();
addChild(myBox);
trace(width, height); // output: 100 100
var myAnotherBox:Shape = new Shape();
myAnotherBox.graphics.beginFill(0xFF00FF, .5);
myAnotherBox.graphics.drawRect(0, 0, 200, 200);
myAnotherBox.graphics.endFill();
addChild(myAnotherBox);
trace(width, height); // output: 200 200
Is there some equivalent implementation in pure Actionscript to reproduce this behavior on "myAnotherBox"?
I already tried:
Change transform matrix;
Change transform pixelBounds;
Change scrollRect;
Apply masks;
And no successful.
Cheers...
You are trying to compare to different things.
In the first example, the width and height are from the UIComponent class, which actually represents a "measured" value, as provided by the Flex Framework.
In the second case, the width and height are the actual size of the rendered shape, as provided by the Flash Player.
If you open the UIComponent's implementation, you will notice that it is actually hiding the original meaning of width and height into $width and $height and provide their own implementation to it.
So to answer your question, you cannot achieve what you want working directly with Shapes (pure Flash components)
Every time you draw something in a graphics context, the width and height will update accordingly.
You options:
draw the first one in one graphics, and the second one in another graphics and measure only the first shape
compute the width and height yourself. This is what actually the containers do, and just skip the includeInLayout=false child components.
If you look up in the UIComponent source code, you'll find, that flag includeInLayout is used in invalidation mechanism (exatcly in size invalidation). If includeInLayout of the component is false, then its parent's size and its size is not recalculated.
Invalidation is native flex framework mechanism, which does not exist in pure AS projects.
You need to override width and height in your container:
override public function get width() : Number {
// place your code here
return 100;
}
override public function get height() : Number {
// place your code here
return 100;
}

Flex: Binding to the Height of the UITextField

I'm having problems binding the height of a UITextField to the y of a VBox and the height of the TitleWindow. I'm trying to adjust the height of the TitleWindow and the height of the VBox so, that the UITextField doesn't overlap the other content.
Alternatively, I've tried setting the height of the UITextField to an explicit height, but I haven't been able to get it to work.
I have to use a UITextField instead of Text, because I'm using Flash Eff2.
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="520"
height="{tf.height + 380}">
<mx:Script>
<![CDATA[
import mx.core.UITextFormat;
import mx.events.ItemClickEvent;
import mx.controls.RadioButton;
import mx.controls.RadioButtonGroup;
import mx.core.UITextField;
import mx.managers.PopUpManager;
[Bindable]
public var tf:UITextField = new UITextField;
[Bindable]
public var myText:String;
[Embed(source="../libs/arial.ttf", fontFamily="ArialEmbedded")]
public const ArialEmbedded:Class;
public function createEffect2():void{
tf.autoSize = TextFieldAutoSize.LEFT;
//tf.height=150;
tf.embedFonts = true;
tf.multiline = true;
tf.text = myText;
tf.width = 400;
tf.wordWrap = true;
var myFormat:TextFormat = new TextFormat;
myFormat.size = 25;
myFormat.blockIndent=50;
this.addChild(tf);
tf.validateNow();
tf.setTextFormat(myFormat);
}
]]>
</mx:Script>
<mx:VBox x="180" y="{tf.height + 140}" width="480" >
<mx:RadioButtonGroup id="choicesRadioButtonGroup" />
<mx:RadioButton groupName="choicesRadioButtonGroup" label="A" horizontalCenter="150"/>
<mx:RadioButton groupName="choicesRadioButtonGroup" label="B" horizontalCenter="150"/>
<mx:RadioButton groupName="choicesRadioButtonGroup" label="C" horizontalCenter="150"/>
</mx:VBox>
</mx:TitleWindow>
I'm getting: Data Binding will not be able to detect assignments to "height".
Any suggestions?
Thank you.
-Laxmidi
If I had to guess, Binding is a Flex construct, not an "ActionScript' construct. Height is a made Bindable in UIComponent, but UITextField does not extend UIComponent. Instead it extends, FlexTextField, which extends TextField (A Closed source Flash class).
You can either extend UITextField and override height to make it Bindable or just use a Flex TextInput class, which does extend UIComponent.

How do I change the size of an HBox in Flex to fit its container?

I create an HBox, fill it with a grid of buttons, and set the scroll policy. When I resize the window, the stage changes size, and so does the HBox ... to a point. Once it reaches the height of the Grid it contains, it stops shrinking, like it has a "min-height". This ruins the scrollbar that I'm trying to establish in this case.
I've set the height to 100%, shouldn't it always take the height of the stage, its parent?
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="init();" horizontalScrollPolicy="off" verticalScrollPolicy="off" width="100%">
<mx:Script>
<![CDATA[
import mx.controls.Button;
import mx.containers.Grid;
import mx.containers.GridRow;
import mx.containers.GridItem;
protected function init():void {
for (var i:int = 0; i < 3; i++) {
var gRow:GridRow = new GridRow();
gRow.percentWidth = 100;
gRow.height = 100;
var gItem:GridItem = new GridItem();
gItem.percentWidth = 100;
var btn:Button = new Button();
btn.label = "BUTTON";
btn.percentWidth = 100;
btn.percentHeight = 100;
gItem.addChild(btn);
gRow.addChild(gItem);
mainGrid.addChild(gRow);
}
}
]]>
</mx:Script>
<mx:HBox width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="on" id="main" clipContent = "true">
<mx:Grid id="mainGrid" width="100%" height="100%" />
</mx:HBox>
</mx:Application>
So it looks like I managed to mention the eventual answer in my question. It's the "minHeight" property folks, looks like it gets set to the contained grids height, and will shrink no smaller. Set it to 0, and your good to go.
I hope this dialog I'm having with myself helps someone else. :)
you can try to give it the heigh of the HBox, as height="{hb.height}" ,hb as id

Resources