Why does Flash use the entire height of a masked object instead of just the visible area?
The problem is if I set the .mask property of a Sprite object, the Sprite object still returns it's full height when I call Sprite.height. So I figured a simple way to overcome this would be to override the property getter.
Now.. even开发者_开发技巧 though that worked, if I add this masked Sprite object to another Sprite object, the new Sprite object will report it's height as the masked Sprite object's height even though I have overridden the property to return only the height of the visible area due to the mask. So it seems Flash ignores the fact that not all of the content is visible but still automatically increases the new Sprite object's height as if there was no mask on the masked Sprite.
So I am wondering if there is a workaround so I can add this masked object to any other DisplayObject knowing it will be resized to only what is visible in the masked object.
Thanks for any help.
EDIT
Here is a code example..
var content:Bitmap = new Bitmap(new BitmapData(50, 100, false, 0x000000));
var container:Sprite = new Sprite();
var mask:Bitmap = new Bitmap(new BitmapData(50, 50, false, 0x000000));
container.mask = mask;
container.addChild(content);
trace(container.height) // this should return 50 instead of 100
So for those interested I managed to come up with a workaround. What really annoys me is that DisplayObject.scrollRect doesn't update the dimensions immediately so until Adobe get off their arse and fix it, here's what you need to do.
The problem with .scrollRect, as I've mentioned, is that it doesn't adjust to the new width and height until after a frame has passed or after a certain amount of time. Either way I've basically built my class so that once .scrollRect is set, I create a timer that runs every millisecond, checking if .width and .height has updated to the new values. Once it has, I dispatch a custom READY event which the parent object listens out for before adding the class to the stage.
Now one very important thing you need to know about this arsehole of a property is that the object of which you are setting the .scrollRect property must be added to the stage before it makes any attempt at updating it's width and height values to those set in the .scrollRect property. So to do this as clean as possible, I pass the Stage object from my main class to the object whose .scrollRect I want to adjust, let's call it MyClass. MyClass sets its .visible property to false then adds itself to the stage. Only once this is done can I now begin my 1ms timer to check if the dimensions have changed correctly after I have set .scrollRect.
So once the timer tick handling function sees the dimensions have changed successfully, MyClass can now dispatch the MyClass.READY event to the main class while at the same time, setting its .visible property to true and removing itself from the stage. When the main class's event listener is triggered, it can now add MyClass to wherever it wants to, knowing that it will have the correct dimensions as set in MyClass.scrollRect.
This has been a great pain to myself and probably many other developers looking for solutions so I hope this has helped you and will suffice for now until Adobe does something about this. Thanks to everyone who posted previously who tried to help, I really appreciate it, thanks!
As xLite mentioned, it will update width and height when it rendered next frame.So you may do something to force it to render.
var content:Bitmap = new Bitmap(new BitmapData(50, 100, false, 0x000000));
var container:Sprite = new Sprite();
content.scrollRect = new Rectangle(0, 0, 50, 50);
container.addChild(content);
new BitmapData(1,1).draw(content);//this line would help
trace(container.height);
If you can't find a direct solution, one thing you could try is this:
- Draw the child (your DisplayObject that includes a mask and maskee) to a BitmapData object.
- Parse through the pixels of the BitmapData object and check the value of the alpha channel using BitmapData's
getPixel32()
method. - Determine the bounding box that bounds all of the non-zero alpha pixels, and use those dimensions.
I'd wrap all of that up in a getMaskedDimensions(child:DisplayObject):Rectangle
method. Let me know if you need more details. Otherwise, good luck with it!
width and height can be overridden. An object will always have an intrinsic width and height corresponding to what's rendered inside of it, and unfortunately that intrinsic width and height will never account for masked areas. getRect and getBounds are not sensitive to masks either, so those aren't sufficient by themselves either.
What you'll need to do is write a recursive method named something like "getMaskSensitiveRect" that is sensitive to masks. Instead of intersecting the result of getRect on each child object, you'd first test if each child's mask property is null, and if it's not null, call getRect on the mask instead of the object, and use that as the child's rectangle to intersect with the rest of the child objects. And you'd definitely have to walk the entire hierarchy of all children, grandchildren, etc. to the deepest level to get an accurate measure, because if even a single mask is not accounted for, it could blow up the size.
Remember to override the setters for width and height, because altering the width or height of a DisplayObject actually alter's it's scale, and it does so relative to that intrinsic size, NOT your overridden width and height. What you'd have to do in the setter is call your getMaskSensitiveRect method, and compute a scale using that and your desired width, then assign the scale to scaleX and scaleY properties.
精彩评论