I discovered last week that scale-9 grids only apply to a DisplayObject and its content, but not its children. At first, I thought, "what!? why not!? that's dumb!" But, after a bit a reflection I realized that it would be *very* tricky to cascade a scale-9 transformation down a display list. I'm not going to attempt to explain why, but just imagine the scenarios where child DisplayObjects straddle the scale-9 grid and you'll realize it quickly moves into "very hard" (and likely slow) territory.
For my scenario, though, the child DisplayObjects simply provided some runtime configurability that once set could be "baked in." This allows you to take the shortcut of flattening the display list to a single bitmap, then applying a scale-9 grid to that. Unfortunately, the Flash Player doesn't allow you to set a scale-9 grid at runtime, probably due to some pre-calculations it does or special structuring of the data.
Searching for answers along these lines I ran across this fantastic post from Ahmed Nuaman:
Scale Any DisplayObject with My ‘ScaleObject’ Class
His theory was dead-on: take a DisplayObject, render it to a bitmap (to flatten it), cut that bitmap into 9 pieces, then override your new class's width/height properties to apply the scale-9 math to the individual pieces.
What I didn't really like was the roundabout way he solved the problem. First of all, the code was far too verbose for my tastes. It also wasn't self-contained, relying on an external bitmap utility function. But most problematic was the use of shapes with bitmap fills: I may be wrong, but I don't see any advantage to this, and it has the distinct disadvantage of being more complex that straight bitmaps and likely less efficient internally in the Flash Player. So, I fixed all that.
-
class ScaleObject extends Sprite
-
{
-
/** Scale9grid pieces. **/
-
private var _tl:Bitmap;
-
private var _tc:Bitmap;
-
private var _tr:Bitmap;
-
private var _ml:Bitmap;
-
private var _mc:Bitmap;
-
private var _mr:Bitmap;
-
private var _bl:Bitmap;
-
private var _bc:Bitmap;
-
private var _br:Bitmap;
-
-
/** Constructor. **/
-
public function ScaleObject(original:DisplayObject, scaleGrid:Rectangle)
-
{
-
_tl = slice(original, 0, 0, scaleGrid.left, scaleGrid.top);
-
_tc = slice(original, scaleGrid.left, 0, scaleGrid.width, scaleGrid.top);
-
_tr = slice(original, scaleGrid.right, 0, original.width - scaleGrid.right, scaleGrid.top);
-
-
_ml = slice(original, 0, scaleGrid.top, scaleGrid.left, scaleGrid.height);
-
_mc = slice(original, scaleGrid.left, scaleGrid.top, scaleGrid.width, scaleGrid.height);
-
_mr = slice(original, scaleGrid.right, scaleGrid.top, original.width - scaleGrid.right, scaleGrid.height);
-
-
_bl = slice(original, 0, scaleGrid.bottom, scaleGrid.left, original.height - scaleGrid.bottom);
-
_bc = slice(original, scaleGrid.left, scaleGrid.bottom, scaleGrid.width, original.height - scaleGrid.bottom);
-
_br = slice(original, scaleGrid.right, scaleGrid.bottom, original.width - scaleGrid.right, original.height - scaleGrid.bottom);
-
}
-
-
/** Create a slice. **/
-
private function slice(original:DisplayObject, x:Number, y:Number, width:Number, height:Number):Bitmap
-
{
-
// render a slice of the original
-
var bd:BitmapData = new BitmapData(width, height, true, 0);
-
bd.draw(original, new Matrix(1, 0, 0, 1, -x, -y));
-
-
// create and position the bitmap
-
var bitmap:Bitmap = new Bitmap(bd, PixelSnapping.AUTO, true);
-
bitmap.x = x;
-
bitmap.y = y;
-
addChild(bitmap);
-
-
return bitmap;
-
}
-
-
/** Width. **/
-
override public function set width(value:Number):void
-
{
-
_tc.width = _mc.width = _bc.width = value - _tl.width - _tr.width;
-
_tr.x = _mr.x = _br.x = value - _tr.width;
-
}
-
-
/** Height. **/
-
override public function set height(value:Number):void
-
{
-
_ml.height = _mc.height = _mr.height = value - _tl.height - _bl.height;
-
_bl.y = _bc.y = _br.y = value - _bl.height;
-
}
-
}
NOTE: The width and height properties specifically don't call the super setters. Doing so causes Sprite to attempt and scale its contents by adjusting scaleX and scaleY.
Hi i have been trawling around trying to find if there is a method to be able to scale from either of the 4 corners. At the moment all i can find is that it only seems to scale from the top left corner? Can it scale from top right?
If you want to scale from a different corner you need to move that corner to the origin. So, do this:
var dispObj:DisplayObject; // you want to scale this from the top right corner
var cont:Sprite = new Sprite;
cont.addChild(dispObj);
dispObj.x = -dispObj.width;
cont.scaleX = 2;
cont.scaleY = 2;
I would like more OO aproach and using one bitmapData drawing on the Sprite instead of having 9 children Bitmaps.
Regards Alex
(please see)
http://winxalex.blogspot.com/2010/03/multilangu...
Correct url:
http://winxalex.blogspot.com/2010/03/how-to-wit...
Correct url:
http://winxalex.blogspot.com/2010/03/how-to-wit...