Animating child elements in Flex 4 - actionscript-3

Anyone know how to animate the size/position of child elements of a layout in Flex 4 ?
Example:
I have a list component with a custom layout. I want when I change the positions of the child elements I want them to animate their move to the new positions.

There is currently no built in way, nor plans, to make animated layouts in Flex 4 :/.
What I've done to make this happen is to animate the setting of "setLayoutBoundsPosition" and "setLayoutBoundsSize" in the layout. So instead of creating a "Move" and "Resize" effect for each item in the layout, which would actually set the width and height explicitly, set the matrix. Then make sure the layout isn't invalidated again (which will happen if you set the width/height directly), or you might start getting an infinite loop. You might have to do some tricks to get this to work right (I haven't got it to work quite right with the Spark Effects, but it's really easy to do with Tweener/Tweenmax, since they have plugins and such to use "setActualSize" or "setLayoutBoundsSize", etc.).
I use TweenMax to animate layouts, and they have a few plugins to make this easy. TweenMax visibly looks like 3x faster (20 fps vs 7fps) than Spark Effects, too, so I'd go with that. It looks something like this, in the updateDisplayList method of your layout.
TweenMax.to(child, duration, {setLayoutBoundsPosition:{x:childX * i, y:childY * i}});

Just like you would normally...
public override function updateDisplayList(width:Number, height:Number) : void {
for (var i:uint = 0; i < target.numElements; i++)
{
var resizeElement:Resize = new Resize(target.getElementAt(i) as IVisualElement);
resizeElement.widthTo = 500;
resizeElement.play();
}
}

Related

Why isn't an animation flipped horizontally when I call setFlipped(true)?

I have some sprites, where the player character is facing to the right.
I can create an animation from those sprites just fine. The problem is, if I want the sprites to face to the left.
I do the following:
Sprite* p = Sprite::createWithSpriteFrameName("Jumping");
p->setPosition(Vec2(_visibleSize.width/2,_visibleSize.height/2));
this->addChild(p);
p->setFlippedX(true);
Vector<AnimationFrame*> animFrames;
float frameRate = 0.32f;
std::vector<std::string> frameNames = {"Running 0","Running 1","Running 2"};
for (int i =0; i<3;i++){
auto frameName = frameNames.at(i);
auto spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(frameName);
ValueMap userInfo;
userInfo["frame_index"] = Value(i);
auto animFrame = AnimationFrame::create(spriteFrame, frameRate, userInfo);
animFrames.pushBack(animFrame);
}
auto animation = Animation::create(animFrames, frameRate);
auto animationAction = Animate::create(animation);
p->runAction(RepeatForever::create(animationAction));
p->setFlippedX(true);
The animation runs, but the animation still shows the player facing to the right. What is the problem? Why doesn't setFlippedX work in this case?
I am using Cocos2d-x 3.13.1. I can't find any bug, so I assume I am doing something incorrectly.
This seems to be a bug, and there doesn't seem to be a way to work around, short of using two sprite sets - one for all the sprites without flipping, and the other set for when the sprites are flipped.
What makes it worse - this means you can't use the animation code if you want flipping, and instead need to implement your own logic, to use the appropriate set of sprites, animations etc.
EDIT: It seems to be fixed in 3.16
Its because you are calling this twice on your code,
p->setFlippedX(true);

AS3: Who should I layout first the parent or the children?

I am building large application in Starling and one of my main problems is who should I layout first: the parent or the children?
What is the default behavior in starling and also in flash:
By default Sprite will get his size based on his children after they have been added to stage.
What if I want to layout the children based on the parent? For example: What if I want to set one of the children to be at position of 20 pixels from the bottom, like bottom menu?
In this case I should:
Add the children
Determine their sizes. If you are building your application cross platform, you need to support many screens, and many times you come to have complicate logic for calculating the scale percentage of your components, which is their size.
Determine your size and layout yourself.
now the bottom menu could be layout at 20 pixels from the bottom. Also it doesn't matter if you place this logic inside the bottom menu or it's parent.
But this not always the case, sometimes you want to layout the parent based on his children. A common example if one of the children is the parent background. In this case you should:
Add the background.
Determinate background size and layout it.
Now you can layout the parent.
But what if I got both of the cases? If one of parent children is background and the other is bottom menu? What if the bottom menu got his own background and other children that need to be layouted base on the parent?
What solution can be used so I will not get lost inside all of this, and can Gazman SDK help here?
What you need is to create layout dependencies between all the components. Each Sprite should have an event that tells us when its layouting is complete.
Now if you have some layouting logic inside the parent that cannot start until its background child is complete layouting, you should create a dependency between the background and the parent. The parent should listen to LayoutComplete event from the background and then he can layout himself, and when he complete layouting he can dispatch LayoutComplete event, and now its child bottom menu can layout himself.
You can implement it yourself or use Gazman-SDK that do exactly that. If you choose Gazman-SDK your code will look like this:
public class ParentClass extends Group
{
private var background:Background = new Background();
private var bottomMenu:BottomMenu = new BottomMenu();
override protected function initialize():void
{
// check if not already added to stage
if(!background.parent){
addChild(background);
addChild(bottomMenu);
}
// Create dependency for background. If background have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// background initialize is complete
if (subscribeForInitilize(background)){
return;
}
// do layouting logic here
}
}
public class BottomMenu extends Group
{
override protected function initialize():void
{
// Create dependency for parent. If parent have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// parent initialize is complete
if (subscribeForInitilize(parent as Group)){
return;
}
// do layouting logic here
}
}

ActionScript 3: Zoom into movieclip while not scaling its childrens

I've included a zoom functionality similar to the one explained at this website:
http://www.flashandmath.com/howtos/zoom/
This works perfectly on my background image(a map, that is), but I want to keep the symbols on my map the same size while zooming in.
I probably could work this out by changing all the children's size when calling the zoom-function, but I am hoping there is some kind of easy code adapt in my children class to make the size of the instances unchangable. Is there?
Thanks!
One crude way, so you don't have to calculate the symbols scale, would be to remove the symbols from the mapDisplayObject so they're no longer a child and instead put symbol placeholders. Then match each symbol's x and y to each place holder, using localToGlobal...
If your children are not scaled or skewed or rotated you can iterate all of them and set transformation matrix to 1/parentScale. Something like:
for each (var child:DisplayObject in parent) {
var matrix:Matrix = child.transform.matrix;
matrix.a = 1/parentScale;
matrix.d = 1/parentScale;
child.transform.matrix = marix;
}

scale9grid functioning on child movieclip

I'm working on a UI project that requires that the automatic resizing buttons (based on label length) have a focus indicator graphic for keyboard or controller focus. This graphic must obviously scale with the parent as you would imagine.
This causes a problem; the parent clip is 9sliced, and that slicing doesn't fall through to the child Sprites/MovieClips of this clip. The focus indicator needs to be an accessible property because it has to be capable of being turned on or off.
Currently the only solution I can image is an extremely programmatical reimplementation of scale9Grid where I split the focus indicator into 9 and alter the 9 parts' properties any time the parent width/height/scaleX/scaleY is changed. This would also mean turning all 9 parts on and off when that button is focused
Is there any better way than that?
I recommend you create some wrapper class AppButton (or may be you already have one since you have some resizing by label functionality) with method setSkin(skin:MovieClip) (where skin is your MovieClip from the library) and overridden setters for width and height, so you can implement here skin resizing logic in method arrange() that called each time width or height are changed.
Skin can be complex - with other movie clips in children (focus border in your case), so don't use scale9Grid for the hole skin, but set sizes directly to the children with set scale9grid them as well, so your arrange method can be like that:
private function arrange():void
{
var child:DisplayObject;
for(var i:int = 0; i < numChildren; i++)
{
child = getChildAt(i);
child.width = width;
child.height = height;
}
}
It's also worth to make one skin format for button skins in project, so you can use one wrapper for all buttons.
Later you can add more features to this AppButton - switching view states on mouse events, setting text label, animating skins and so.
This approach work for me for many years, we have base ToggleButton and LabelButton extends ToggleButton classes, and extends them in every project with custom skin parsing and arranging.

drawing on CandlestickSeries LineSeries makes candles narrower

I'm, using Flex 4.5.
In my application I have a CandlestickChart with basic CandlestickSeries.
I give the user the ability to add a linechart on top of the candlesChart by adding a LineSeries to the CandleStickChart as explained in adobe's docs here: here
My problem is that when the line is added it changes the shape of the candle to be narrower. Moreover, every line that is added is making the candle be narrower.
I've looked around and found this thread in adobe's forums: "CandlestickChart problem with LineSeries" which describes the exact same problem.
Unfortunately, the thread is still not answered.
Does any one knows a solution for this problem?
Thanks in advance,
Ravid
Well, the solution I found is not nice and better solutions are still appreciated but for those of you that have the same problem this solution worked for me:
The problem occurs because the candle's default item renderer uses the item's width to calculate the size of the candle which is make sense.
The problem, is that when you add another series there is a bug and the item's width is changed thefore the candle is changed.
My solution is to create a copy of the default item renderer and draw the candles based on the graph's width and number of candles you wish to put there (so you don't use the item's width).
It fixes the problem but if you use tooltips functionality than it kinda messes its placement relative to the candle.
I know this answer is a bit late, but in case it helps anyone else, here's what I did.
(It's not thoroughly tested either)
Make a class that extends the CandleStickChart class and simply override the "applySeriesSet" function as so:
override protected function applySeriesSet(seriesSet:Array /* of Series */,
transform:DataTransform):Array /* of Series */
{
// filter out the non-candlestick series
var filteredSeriesSet:Array = new Array();
for each(var series:Series in seriesSet){
if(series is CandlestickSeries) filteredSeriesSet.push(series);
}
// call the CandlestickChart applySeriesSet function with the filtered set, ignore return value
super.applySeriesSet(filteredSeriesSet, transform);
// do the code that the CartesianChart applySeriesSet function would have done, but with the unfiltered seriesSet
// would have preferred to do something like super.super.applySeriesSet(seriesSet, transform);
var n:int = seriesSet.length;
for (var i:int = 0; i < n; i++)
{
var newSeries:IChartElement = seriesSet[i];
if (newSeries is Series)
customizeSeries(Series(seriesSet[i]), i);
}
return seriesSet;
}