I have custom flex component inherited from UIComponent (compiled, no source code access). It has fixed width-to-height proportions and it's scalable. If I set its width and height to 100%, it's trying to fit parent's size, but it keeps width-to-height proportion, so if it's proportion does not equal parent's proportion, there can appear empty space near this component when resizing parent.
What I need, is to fit my component completely to parent's size. Is there any nice way to do this? I could listen to parent's resize event, and play with component's scaleX and scaleY, but may be any better way exists to solve my problem (any property?). Thanks.
A great way is to use greensock's AutoFitArea.
Coding is as simple as the following
var area:AutoFitArea = new AutoFitArea(this, 50, 70, 300, 100);
area.attach(myImage, {scaleMode:ScaleMode.PROPORTIONAL_OUTSIDE, crop:true});
which would constrain whatever is inside do the given dimensions (300,100) from there on out, you can just change the area's width and that will figure it all out for you.
hope it helps
Personally, what I would do is have the component within the parent set at width/height 100%, then within the component itself, override the updateDisplayList function (which returns the unscaled width/height) and then resize whatever children you're trying to display depending on the width/height of this container. Something like this:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
if(this._child!= null)
{
if(unscaledWidth > unscaledHeight)
{
this._child.height = unscaledHeight;
this._child.scaleX = this._video.scaleY;
}else{
this._child.width = unscaledWidth;
this._child.scaleY = this._video.scaleX;
}
}
}
Should do it.
Should the component keep its proportion? If not, you could just, as you said, listen to the resize event of the parent and set the width and height to the components values.
If the component should keep its proportion you could resize the background of your component so that it fits the parents size and resize the content of you component with its proportion seperatly.
Related
I am conceiving a horizontal bar containing items.
They must all be of same width, having the same spacing between them.
They can expand as much as they want vertically (
stackblitz here
Problem:
How to automatically set the width of the row elements? Here I simply put a value that looks good: width:200px.
I want them to have a width dependent on the number of element per row.
What I tried:
Using elementRef in Horizontile (component holding the individual tiles, displaying with *ngFor) to get the width of this element:
currentWidth:number;
constructor(private el:ElementRef) {}
ngAfterViewInit(): void {
this.currentWidth=this.el.nativeElement.offsetWidth;}
it returns 5. (??) Using .width returns nothing. Also this is not recommended, I'd like another solution, less coupling.
I noticed I can make use of width:inherit; in the css of the individual tile component, which allows me to set the style from the horizontal list component.
<app-tile [style.width.px]="0.9*currentWidth/nDisplayedTiles" [tile]="item"></app-tile>
As the currentWidth value is zero, of course it doesn't work;
I tried setting it in % but the inherits css tag keeps the %, which is not the intended effect.
Why is the app-tile styling not cared about if inherits is not set?
I tried using ViewEncapsulation but it had no effect either.
This looks like a trivial matter though: did I just miss something?
You can use the offsetParent (link) width and create a method to return the value on each of the cells and call it in your [style.width.px], something like the following will work.
The HTMLElement.offsetParent read-only property returns a reference to the element which is the closest (nearest in the containment hierarchy) positioned ancestor element.
stackblitz
ngAfterViewInit(): void {
//added this as the compiler was throwing ExpressionChangedAfterItHasBeenCheckedError
setTimeout(() => {
this.currentWidth=this.el.nativeElement.offsetParent.clientWidth;
});
}
getWidth(): number{
let width:number = 0;
//you may need to change this value to better display the cells
let multiplier = 0.7;
width = (this.currentWidth * multiplier) / this.ndisplayTiles;
width = Math.round(width);
return width;
}
<app-tile [class]="'layout-tile'" [tile]="item" [style.width.px]="getWidth()">
</app-tile>
I am waiting to expand and contract a linear layout.
The linear layout height will be set to 0dp pixels in the beginning and once a user selects a certain button then that layout height will be expanded to MATCH_PARENT.
Once the user selects the button again the linear layout is given a height of 0dp again.
Please any help will be awesome. Thank you.
You may try something like below to set the height to 0
// Get your linearlayout
LinearLayout layout = (LinearLayout)findViewById(R.id.mylinearlayout);
// Gets the layout params that will allow you to resize the layout
LayoutParams params = layout.getLayoutParams();
// Changes the height and width to the specified *pixels*
params.height = 0;
For mobile Flex / Flash Builder, is it better to detect screen dimensions using systemManager.screen.* or Stage.* - and why?
In most cases, it is more reliable to use FlexGlobals.topLevelApplication.width and FlexGlobals.topLevelApplication.height.
When building apps, I think it is more important to know the space I have to work with than it is to know the actual screen dimensions.
To get this information, I would tie into the Flex Framework and use the unscaledWidth and unscaledHeight properties passed into the updateDisplayList() method.
The question is, why do you need to detect screen dimensions. If you just need to use them to size and position a component's children, then I believe the solution I describe above is the best one. If you need this information for some other reason, explain.
This is one way to size and position a label inside the updateDisplayList of it's container:
protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledwidth, unscaledHeight);
// first position it
// you could also use this.myLabel.move(x,y) method to position the element
this.myLabel.x = 0;
this.myLabel.y = 0;
// then size it
// sizing to 100% height/width of container
this.myLabel.height = unscaledHeight;
this.myLabel.width = unscaledWidth;
// or you could also use setActualSize; which is slightly different than setting height and width
// becaues using setActualSize won't set the explicitHeight/explicitWidth, therefore measure will still
// execute
this.myLabel.setActualSize(unscaledWidth, unscaledHeight)
// or you could set the label to it's measured height and measured width
this.myLabel.height = this.myLabel.getExplicitOrMeasuredHeight();
this.myLabel.width = this.myLabel.getExplicitOrMeasuredWidth();
}
I have a component ObjectHolder which extends UIComponent that holds many children UIComponents. However, after using addChild() to add these children to ObjectHolder, its width and height remain zero. Is it possible for the UIComponent to automatically expand to the size of its containing children components?
public class ObjectHolder extends UIComponent
{
public function ObjectHolder()
{
var c1:UIComponent = new UIComponent();
c1.graphics.beginFill( 0xffffff );
c1.graphics.drawRect(0, 0, 100, 100);
addChild( c1 );
trace( this.width ); // Displays zero
}
}
To change the component's size you should implement measure() method. But you should also follow other recommendations on creating custom components. In your case you should create and add child component in createChildren() method.
Is it possible for the UIComponent to automatically expand to the size
of its containing children components?
The formal answer is no. A component is never responsible for setting it's own height and width values; it is only responsible for sizing and positioning it's children based on the values set by that component's parent.
If you implement a measure() method in your component, you can use it to set the measuredWidth and measuredHeight of your component. This will, in essence, be a suggestion that you provide to your parent's container on what is the ideal size you need to position and size all your child elements properly. Your own components should be sized and positioned in updateDisplayList() based on the unscaledWidth and unscaledHeight values passed in.
Most of the time the Flex default containers will honor these sizing values; although there are situations where they will not be. For example, if the size the child container needs is more than the size of the parent.
I thought I had a handle on AS3, DisplayObjectContainers, etc. but this basic thing is really confusing me: changing the width/height of a sprite does not affect it's visual contents - either graphics drawn within it or any children it may have.
I have searched around and found an Adobe page that represents my own little test code. From that page, I would expect the sprite to increase in visual size as it's width increases. For me, it doesn't. (http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/display/DisplayObject.html#width)
width property
width:Number [read-write]
Indicates the width of the display object, in pixels. The width is calculated based on the bounds of the content of the display object. When you set the width property, the scaleX property is adjusted accordingly, as shown in the following code:
My code below doesn't affect the visual display at all - but it does set the width/height, at least according to the trace output. It does not affect the scaleX/scaleY.
What the heck am I missing here??
My setup code:
testSprite = new SpriteVisualElement();
var childSprite:SpriteVisualElement = new SpriteVisualElement();
childSprite.graphics.beginFill(0xFFFF00, 1);
childSprite.graphics.drawRect(0, 0, 200, 100);
childSprite.graphics.endFill();
childSprite.name = "child";
testSprite.addChild(childSprite);
container.addElement(testSprite);
testSprite.addEventListener(MouseEvent.CLICK, grow);
}
public function grow(event:MouseEvent):void
{
event.target.width += 5;
event.target.height += 5;
trace("grow", event.target.width);
}
If I understand the code correctly; you are changing the width / height of the sprite. But you are doing nothing to change the width/ height of the sprite's children.
In the context of a Flex Application, you can use percentageWidth and percentageHeight on the child to resize the child when the parent is resized. You could also add a listener to the the resize event and adjust sizing that way; preferably tying in to the Flex Component LifeCycle methods somehow.
I believe these approaches are all Flex specific, and dependent upon the Flex Framework. Generic Sprites, as best I understand, do not automatically size themselves to percentages of their parent container; and changing the parent will not automatically resize the parent's children.
I bet something like this would work:
public function grow(event:MouseEvent):void
{
event.target.width += 5;
event.target.height += 5;
childSprite.width += 5;
childSprite.height += 5;
trace("grow", event.target.width);
}
First, if you have a problem with a flex component, you can look over its source code.
In my environment, (as I installed flex SDK to C:\flex\flex_sdk_4.1), the source code for SpriteVisualElement is located at
C:\flex\flex_sdk_4.1\frameworks\projects\spark\src\spark\core\SpriteVisualElement.as
In the source code, you'll find that width property is overridden :
/**
* #private
*/
override public function set width(value:Number):void
{
// Apply to the current actual size
_width = value;
setActualSize(_width, _height);
// Modify the explicit width
if (_explicitWidth == value)
return;
_explicitWidth = value;
invalidateParentSizeAndDisplayList();
}
So, you cannot expect the auto-scaling of the component.
Making custom components will be one solution.
Here is a sample implementation of custom component.
Custom Component Example - wonderfl build flash online