Rotating a Label 90 degree in an Item Renderer - apache-flex

I'm trying to rotate a label on my item renderer.
When I rotate it 45 degrees, it's working just fine but when I rotate it 90 degrees,
which is what I wanna do, label is rotating but after list created,
rotated labels are stepping up each other.
I can select the 45 degree ones but it seems like 90 degree ones has no
width at all. When I declare width and height and padding but that did not solve it too.
How can I make my labels 90 degree without making them step up each other?
My item renderer:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" >
<fx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
dateLabel.text = data.date;
}
]]>
</fx:Script>
/* When rotation is 90, my labels are just stepping up eachother */
<s:Label id="dateLabel" rotation="45"/>
</s:ItemRenderer>

The BasicLayout that your renderer is using (by default) doesn't respect the transformations that occur in the object's width/height/position/etc when you rotate it. It still tries to layout the objects as if they were not rotated.
However, if you use any other layout, like VerticalLayout or HorizontalLayout, the objects new dimensions (after rotation) are used.
I may not be explaining the above properly, but a simple solution to this problem is just to add a layout declaration to your renderer:
<s:layout>
<s:VerticalLayout/>
</s:layout>

Related

Smooth scrolling a Spark List with variable height items using the mouse wheel

We have a list of variable height items that we display in a Spark List control. When the user clicks and drags the vertical scrollbar the list scrolls smoothly. When the up/down arrows are used it moves in small and discrete steps. When the mouse wheel is used the list scrolls in very large discrete steps that is problematic for the user.
We would like to enable smooth scrolling for the mouse wheel. The height of our items vary significantly and it is easy to get lost when you scroll with the moouse due to the discrete scrolling.
Our implementation is fairly simple:
<s:List id="chartList"
dataProvider="{pm.charts}"
itemRenderer="charts.ChartItemRenderer"
horizontalScrollPolicy="off"
verticalScrollPolicy="on"
useVirtualLayout="false"
cachePolicy="auto">
</s:List>
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="false"
xmlns:charts="charts.*"
>
<fx:Script>
<![CDATA[
private var _canvas:BitmapData;
public function set canvas(value:BitmapData):void
{
_canvas = value;
}
[Bindable]
public function get canvas():BitmapData
{
return _canvas;
}
public function render(x:int,y:int, data:int):void
{
_canvas.draw(this);
}
]]>
</fx:Script>
<charts:DefaultChartContainer
chart="{data}"
cachePolicy="on"/>
</s:ItemRenderer>
There does not appear to be an out of the box method for implementing smooth scrolling in a Spark List. How would one go about implementing smooth scrolling in a spark list for variable height items?
Edit:
Here is another way to do this:
http://forums.adobe.com/message/3844410#3844410
Ok, so this wont be easy, but it is doable.
1) Create a custom skin for your list
2) In the custom skin, replace the scroller with a custom scroller (MyScroller)
3) Create a new class that extends Scroller, called MyScroller
4) Adobe in their infinite wisdom made skin_mouseWheelHandler private - which they seem to do all over the place, so you would have to override something higher up, maybe attachSkin and detachSkin. Or you could try adding your own skin_mouseWheelHandler with a higher priority in attachSkin and prevent default on it so the default does not get called.
5) Replicate the code in skin_mouseWheelHandler, and modify it to suit your requirements.
Like #Sunil_D. suggested, listening the mousewheel event and manually adjusting the HorizontalScrollPosition is an easy way to handle this. Add the EventListener for your component
chartList.addEventListener(MouseEvent.MOUSE_WHEEL, chartList_mouseWheelHandler);
and increase/decrease the horizontalScrollPosition with, for example, multiples of event.delta
protected function chartList_mouseWheelHandler(event:MouseEvent):void
{
chartList.verticalScrollPosition -= (event.delta * SOME_CORRECT_VALUE);
}
Finding the proper SOME_CORRECT_VALUE might need some experimenting, but it shouldn't be to hard to find.

How to find the element offset in a group?

I have a visual element that is nested in two groups. How would I find the X and Y offset of that element from a parent group?
Here is the code:
<group id="rootGroup">
<group id="parentGroup" x="30" y="50">
<button id="myButton" x="40" y="20" />
</group>
</group>
The button position can change over time as well as the parent groups position. So I was trying to use something like localToGlobal.
Below is an example application that shows how to do this. The basic idea is convert the target object's (the button) coordinates to global coordinates with localToGlobal(). Then use globalToLocal() to convert the global coordinates into the desired coordinate space.
The most important step is the first part. To convert the button's coordinates into global coordinates, we actually use the parent of the button -- because the button "exists" in it's parent's coordinate space. This is always a little confusing when I do it :)
Run this app and play with it. To really test it, add one more BorderContainer around the "rootGroup" and offset "rootGroup" by a few pixels so that the root's coordinate space is not the same as the global coordinate space.
<?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"
creationComplete="onCreationComplete()">
<fx:Script>
<![CDATA[
private function onCreationComplete():void
{
var p:Point = new Point(childButton.x, childButton.y);
trace(p); // (x=50, y=50)
// convert the button's coordinates to Global coordinate space
// note since the button exists in the parent object's coordinate plane
// you do this conversion using the parent
var global:Point = parentGroup.localToGlobal(p);
trace(global); // (x=151, y=151) <-- 1 extra pixel from border of the BorderContainer
// now that we have global coordinates, use globalToLocal() to convert
// these coordinates into the desired coordinate plane
var rootLocal:Point = rootGroup.globalToLocal(global);
trace(rootLocal); // (x=151, y=151)
var parentLocal:Point = parentGroup.globalToLocal(global);
trace(parentLocal); // (x=50, y=50)
}
]]>
</fx:Script>
<s:BorderContainer id="rootGroup" borderColor="#FF0000">
<s:BorderContainer id="parentGroup" x="100" y="100" borderColor="#00FF00">
<s:Button id="childButton" x="50" y="50" label="Click Me"/>
</s:BorderContainer>
</s:BorderContainer>
</s:Application>

Problem with scrolling a sparks list with TileLayout in Flex 4.5

I'm experiencing a very strange behavior with a spark list with TileLayout placed inside a scroller. Basically, I want to have a title area above my list that scrolls away when the user scrolls down the list. To do this I put the title and the list inside a Group and wrapped the group inside a scroller with width and height = 100%. I also set the verticalScrollPolicy to off on the list to make sure everything scrolls together.
The problem is that if the list has the default VerticalLayout everything works fine but if you assign a TileLayout to the same list it only partially renders the items (about 30 items when testing on iPhone 4).
Here's the fully functioning code. Try it like this first, then try removing the <s:layout> part to confirm that it works well with VerticalLayout:
<?xml version="1.0" encoding="utf-8"?>
<s:View
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var myAC:ArrayCollection = new ArrayCollection([
"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72","73","74","75","76","77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98","99","100"
]);
]]>
</fx:Script>
<s:Scroller width="100%" height="100%">
<s:VGroup>
<s:Label text="TITLE" width="100%" height="200" backgroundColor="#333333" color="#EEEEEE"/>
<s:List
id="list"
width="100%"
verticalScrollPolicy="off"
dataProvider="{myAC}" >
<s:layout>
<s:TileLayout
columnWidth="200"
rowHeight="200"
useVirtualLayout="true" />
</s:layout>
</s:List>
</s:VGroup>
</s:Scroller>
</s:View>
What am I doing wrong? Or is this a bug?
You need to calculate and set the height of the list. You can easily calculate it by figuring out the number of rows times the height of a row as below:
private function listHeight():Number {
// In this example you had 3 items to a row on the iPhone4 emulator
var numRows:Number = Math.ceil(myAC.length / 3);
// The height of the row (200) plus the gap between rows (6)
var rowHeight:Number = 200 + 6;
return numRows * rowHeight;
}
This is not a perfect solution, especially if you are targeting multiple screen densities (as the number of items per row will differ from device to device), but it might get you on the right track.
A better solution would be to extend the list component in an ActionScript class and add a header which you can set.

Does the ScaleX scaleY makes the Width and height change?

Am working in flex 4 the sample mxml is
<?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"
minWidth="955" minHeight="600" >
<fx:Script>
<![CDATA[
protected function button1_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
trace(hgroup.width ,hgroup.height);
hgroup.scaleX = 1.5;
hgroup.scaleY = 1.5;
trace(hgroup.scaleX, hgroup.scaleY);
trace(hgroup.width ,hgroup.height);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:HGroup id="hgroup" width="85%" height="85%" clipAndEnableScrolling="true">
<s:Button click="button1_clickHandler(event)" label="Click to Scale"/>
</s:HGroup>
</s:Application>
If i debug
on a first button click the trace shows like this
870 535
1.5 1.5
870 535
on second click of button the trace shows like this
580 356.6666666666667
1.5 1.5
580 356.6666666666667
on the perpendicular clicks it shows as like the second click
my question is does the scaleX scaleY affects the width height??
please guide me i need increase in width height perpendicular
with the scaleX scaleY
Yes, scaling does affect width and height. I'm a little surprised that isn't reflected immediately in the third trace statement but my guess is it has something to do with the invalidation and redrawing of flex components. I double checked on a simple non-flex app and the properties for width and height updated immediately.
=============
Finally i got Answer the scaling will not change width height. but what the thing is i used the percent width height so it get reduced. I double checked with the static width height i does not get increased but when the width height increased the scaleX scaleY increases simultaneously.Keep this in the Mind
Thanks all for the support
by Sudharsanan
~~~~Happy Coding~~~~~
Scaling effects the width or height of the object you scaled.
The contents of hgroup ( aka myBTN )will be unchanged.
What would be the point of scaling something if it didn't get bigger or smaller
protected function button1_clickHandler(event:MouseEvent):void{
// TODO Auto-generated method stub
trace( hgroup.width ,hgroup.height);//52 22
trace( myBTN.width ,myBTN.height);//52 22
hgroup.scaleX = 1.5;
hgroup.scaleY = 1.5;
hgroup.validateNow()
trace( hgroup.scaleX, hgroup.scaleY);//1.5 1.5
trace( hgroup.width ,hgroup.height);//78 33 // notice the scaling changed the container
trace( myBTN.width ,myBTN.height);//52 22 // here is where you see the sizes unchanged
}
<mx:Canvas id="hgroup" >
<mx:Button id="myBTN" label="Click" click="button1_clickHandler(event)" />
</mx:Canvas>
And to answer HotN on why there isn't an immediate update is because this is a display object and as such will follow the uiComponent framework.
To make the changes immediately you have to call "validateNow" To update the display list instead of waiting for the next frame.

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;
}

Resources