I created a SkinnableContainer runtime because I want to set some style properties to it, then based on some external data I need to create a new SkinnableContainer and add it as children of the first one. This children height can be greater than the parent container.
How can I create a SkinnableContainer runtime with some scrollbars?
I read in the documentation that I need to create a new Skin.
It is possible runtime to achieve the same result ?
// ... in a container ...
var father = new SkinnableContainer();
this.addElement(father);
var child = new SkinnableContainer();
// ... some initialization... child is filled with some other elements from outside
father.addElement(child);
// ... now if child.height > father.height
// I want to add a vertical scrollbar
You could always put the child in a Scroller control.
For example:
var father = new SkinnableContainer();
this.addElement(father);
var scroller = new Scroller();
var child = new SkinnableContainer();
// ... some initialization... child is filled with some other elements from outside
// scroller.addElement(child); // wrong because you cannot add element to a scroller
scroller.viewport = child.contentGroup; // but you can set this to an IViewport
father.addElement(scroller);
father.addElement(child);
Related
I need to dynamically create a ui widget with a parent div.id='myDivId', which is a google map control.
var centerControlDiv = document.createElement('div');
var centerControl = new CenterControl(centerControlDiv, map);
centerControlDiv.index = 1;
centerControlDiv.id = 'myDivId';
map.controls[google.maps.ControlPosition.TOP_CENTER].push(centerControlDiv);
// $('#myDivId') causes exception as $('#myDivId') is not created on
// map as a DOM element yet.
var uiWidget = new uiWidget('myDivId');
// $(#myDivId) is used in class uiWidget().
class uiWidget {
constructor(divId) {
this.id = divId;
// It should fail here due to this.$div property, as
// div 'myDivId' is not a DOM element yet by google map
// controls API.
this.$div.click($.proxy(this.event_click, this));
}
get $div() {
return $(‘#’ + this.id);
}
event_click(eve) {
}
}
But, there is no event of when this parent div is created. Therefore, the child ui widget can't be created at correct time.
How to know parent div with id 'myDivId' is created?
You are trying to reference a DOM element by ID as a child of document when that element has only been created but not yet added to the document.
But you already have a reference to the #myDivId element in the centerControlDiv variable, so you don't need to use the ID to reference it. Just change this line:
$('#myDivId').append("<div>UI widget</div>");
to:
$(centerControlDiv).append("<div>UI widget</div>");
Put another way, to answer your question "How to know parent div with id 'myDivId' is created?", that div already is created - you created it in the document.createElement('div') call. It just isn't a child of document yet.
So when you use $('#myDivId'), or similar calls like document.getElementById('myDivId'), those calls can't see it. It's just a standalone element that you have a reference to, so you can access it through that element instead of looking it up in the document DOM.
Update based on your latest code:
To apply this principle to your uiWidget class, you can have the class work with the actual div element you created instead of accessing it by ID. Even better, since you're using jQuery, pass it a jQuery object from the beginning, like this:
var uiWidget = new UiWidget( $(centerControlDiv) );
class UiWidget {
constructor($div) {
this.$div = $div;
this.$div.click($.proxy(this.event_click, this));
}
// ...
}
As you can see, the code no longer requires the div ID at all, and it doesn't need the get $div() either. $div and this.$div are already a jQuery object wrapping your centerControlDiv.
I also changed the name of the class to UiWidget to follow recommended JavaScript style and avoid conflict with the uiWidget variable that holds an instance of the class.
I made this class, which is an ItemRenderer class, used in a DataGroup ( mobile application ),
and I am not entirely sure if I did the right thing or not, my issues are :
Is there a better way to show the image, which is 80x80 and directly loaded from the server;
How to make the height of the row dynamic, I mean, depending on the height of the 3 StyleableTextFeild
Is this the right way to add the listener on the image, that will trigger a simple HTTPService,
Here is the functions from the class, Any help would be much appreciated !!
Image
Declared it as a simple image :
var logo:Image;
On override createChildren
logo = new Image();
addChild(logo);
And I added on set Data
logo.source = "http://192.168.0.15:3000/"+value.logo_thumb_url;
Size
override protected function measure():void {
measuredWidth = measuredMinWidth = stage.fullScreenWidth;
measuredHeight = measuredMinHeight = 100;
}
Listener
override public function set data(value:Object):void {
tel.text = String(value.Tel);
description.text = String(value.Descricao);
nome.text = String(value.Nome);
logo.addEventListener(MouseEvent.CLICK, function():void{
var service:HTTPService = new HTTPService();
service.url = value.targer;
service.method = "GET";
// setting headers and other variables ...
service.send();
});
}
You can use URLLoader or Loader for loading the image if you are planning to cache the image on the client side, if you cache the image, it wil help you not load the image again when the users scrolls through the list. (What you have done is Ok, but you will hit performance issues)
For variable row height, if Datagroup does not work, use List. find it here Flex 4: Setting Spark List height to its content height
There should be a buttonMode property for some items, make it buttonMode for the logo, for variable row height, find something related to wordWrap and variableRowHeight properties on the datagroup.
There are a few suggestions, what you have coded is good, but, instead of adding the listeners on set data, add it in creation complete, as it is more appropriate. Also, the event listeners has to be weak referenced, http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/EventDispatcher.html#addEventListener()
scrollPane.setSize(400,400);
scrollPane.source=emptyc;
Where emptyc is a container in which I add content dynamically (i.e. by addChild method) doesn't work. It simply doesn't scroll at all.
Neither does work if I add content using scrollPane as a container itself (i.e.:
scrollPane.addChild(myChild);
The problem is the ScollPane instance has no clue you've updated it's content (added a child to emptyc/etc.) so you need to tell it to update().
Here's a basic example:
var b:BitmapData = new BitmapData(2,2,false,0xFFFFFF);
b.setPixel(0,0,0);b.setPixel(1,1,0);
var s:Shape = new Shape();
var sp:ScrollPane = new ScrollPane();
sp.scrollDrag = true;
sp.source = s;
addChild(sp);
s.graphics.beginBitmapFill(b);
s.graphics.drawRect(0,0,1000,1000);
s.graphics.endFill();
sp.update();
Notice that you get the same behaviour you mention if you comment out sp.update();.
Also, there's an example in the documentation.
I want to control which DisplayObject is displayed on the front or on the back.
I can control that with zIndex style in css.
How can I do that in as?
Look at setChildIndex()
Here's a quick function that will let you place something at the highest depth:
function toTop(child:DisplayObject):void
{
if(child.parent)
{
child.setChildIndex(
child.parent.numChildren - 1
);
}
}
To control the z-order of the displayObjects use setChildIndex().
Lowest indexed children are displayed at the bottom.
Highest indexed children are displayed at the top.
To change the zorder of the children, use setChildIndex, to illustrate:
var container:Sprite = new Sprite();
var child1:Sprite = new Sprite();
var child2:Sprite = new Sprite();
var child3:Sprite = new Sprite();
container.addChild(child1); // bottom
container.addChild(child2); // middle
container.addChild(child3); // top
container.setChildIndex(child3,0); // child3 would now be at the bottom
There are even more options than only setting the 'z-index', you have full control on the layers:
getChildAt(index:int):DisplayObject
Gets an object from certain index
getChildIndex(child:DisplayObject):int
Gets a index from certain object
addChild(child:DisplayObject):DisplayObject
addChildAt(child:DisplayObject, index:int):DisplayObject
Adds a object on top (addChild) or at certain index (addChildAt)
swapChildren(child1:DisplayObject, child2:DisplayObject):DisplayObject
swapChildrenAt(index1:int, index2:int):void
Swap objects with eachother of by its 'z-index'
Is there a way to make a display object always be at the top of the display list?
For example, I know you can set the childIndex, i.e:
setChildIndex(myDisplayObject, numChildren-1);
But is there a way that an object has sensed that something else has been added to the display list and restack themselves accordingly?
You can listen to the Event.ADDED event on the container. This event will bubble up, so you'll get called whenever a display object is added to the container or any of its children.
Here's an example of how you could do this. You'll see the black box always stays on top.
var container:DisplayObjectContainer = this; // this is a frame script but just change this line as necessary
container.addEventListener(Event.ADDED,handleAdded,true);
function handleAdded(e:Event):void {
// this if tries to cover some edge cases, unlikely to happen in your code, from your description
if(container == topElement.parent && container.numChildren > 0 && container.getChildIndex(topElement) != container.numChildren - 1) {
container.setChildIndex(topElement,numChildren - 1);
}
}
function getSprite(c:uint):Sprite {
var sp:Sprite = new Sprite();
sp.graphics.beginFill(c);
sp.graphics.drawRect(0,0,100,100);
sp.graphics.endFill();
return sp;
}
var topElement:Sprite = getSprite(0);
container.addChild(topElement);
var sp:Sprite = getSprite(0xff0000);
container.addChild(sp);
sp.addChild(getSprite(0xff00));
var sp2:Sprite = getSprite(0xff);
container.addChild(sp2);
However, I think it's much simpler and cleaner just to have 2 containers, say, top and bottom, kind of like layers. In top you'd add the element that always must be on top (or this could be your element as you probably don't need to have this extra container). In bottom you'd add and remove whatever you want. Then you can forget about manually restacking stuff (at least to keep the top element atop).
You can override the addChild() method in the parent object. In that method you can move your child to the top using
setChildIndex(myDisplayObject, numChildren-1);
In this way everytime an object is added to the parent, the parent moves your object to the top.